From afa1e9841799a61eab944bbcee7cbe6b6aca90ec Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 28 Aug 2020 14:42:23 -0700 Subject: [PATCH 0001/1057] Create VCN subdirectories and add relevant owners This change simply sets up owners files in VCN subdirectories Bug: 163431877 Test: No code changes; compiles. Change-Id: I01f40bf75911592bab709d3ce070fb86ef270fe8 --- Vcn/service-b/src/com/android/server/vcn/OWNERS | 7 +++++++ Vcn/tests/unit/OWNERS | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 Vcn/service-b/src/com/android/server/vcn/OWNERS create mode 100644 Vcn/tests/unit/OWNERS diff --git a/Vcn/service-b/src/com/android/server/vcn/OWNERS b/Vcn/service-b/src/com/android/server/vcn/OWNERS new file mode 100644 index 0000000000..33b9f0f75f --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com \ No newline at end of file diff --git a/Vcn/tests/unit/OWNERS b/Vcn/tests/unit/OWNERS new file mode 100644 index 0000000000..33b9f0f75f --- /dev/null +++ b/Vcn/tests/unit/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com \ No newline at end of file From 7c2f307b29682fa92c0c6a6cca1b6442da80ee75 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 8 Oct 2020 14:25:55 -0700 Subject: [PATCH 0002/1057] Add VCN owners and subdirectories This change simply sets up owners files in VCN subdirectories Bug: 163431877 Test: atest CtsVcnTestCases Change-Id: I5863c915007025180cd811d451c1201d9ab402ef --- Vcn/tests/cts/OWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Vcn/tests/cts/OWNERS diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS new file mode 100644 index 0000000000..350d2db8eb --- /dev/null +++ b/Vcn/tests/cts/OWNERS @@ -0,0 +1,2 @@ +nharold@google.com +junyin@google.com \ No newline at end of file From 4924f3acd0c930bf6bea5403ae1cb2e793f90a82 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 13 Oct 2020 15:48:44 -0700 Subject: [PATCH 0003/1057] Add VCN file owners for android.net.vcn This change adds owners for the VCN files in the android.net.vcn package Bug: 163431877 Test: No code changes; FrameworksNetTests passing Change-Id: I7406083b958a9fd5f1b02c2e2046a9c686622f60 --- Vcn/framework-b/src/android/net/vcn/OWNERS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/OWNERS diff --git a/Vcn/framework-b/src/android/net/vcn/OWNERS b/Vcn/framework-b/src/android/net/vcn/OWNERS new file mode 100644 index 0000000000..33b9f0f75f --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com \ No newline at end of file From 6e0ef5dd77bd7d2becf105224745a8574caf75bc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 28 Jul 2020 13:42:04 -0700 Subject: [PATCH 0004/1057] Add shell VcnManagementService This patch adds a shell of the VcnManagementService and VcnManager Bug: 163431877 Test: Compiles, Boots Change-Id: I1f3d8ab9c9bff7d419ea6d3edaae3b6b41b1d775 --- .../net/vcn/IVcnManagementService.aidl | 23 ++++ .../src/android/net/vcn/VcnManager.java | 48 ++++++++ .../android/server/VcnManagementService.java | 103 ++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnManager.java create mode 100644 Vcn/service-b/src/com/android/server/VcnManagementService.java diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl new file mode 100644 index 0000000000..af06906ca2 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -0,0 +1,23 @@ +/* + * Copyright 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.vcn; + +/** + * @hide + */ +interface IVcnManagementService { +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java new file mode 100644 index 0000000000..d563b03501 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -0,0 +1,48 @@ +/* + * 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.vcn; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.SystemService; +import android.content.Context; + +/** + * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks + * + * @hide + */ +@SystemService(Context.VCN_MANAGEMENT_SERVICE) +public final class VcnManager { + @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + + @NonNull private final Context mContext; + @NonNull private final IVcnManagementService mService; + + /** + * Construct an instance of VcnManager within an application context. + * + * @param ctx the application context for this manager + * @param service the VcnManagementService binder backing this manager + * + * @hide + */ + public VcnManager(@NonNull Context ctx, @NonNull IVcnManagementService service) { + mContext = requireNonNull(ctx, "missing context"); + mService = requireNonNull(service, "missing service"); + } +} diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java new file mode 100644 index 0000000000..db7e16ca8b --- /dev/null +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -0,0 +1,103 @@ +/* + * 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; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.vcn.IVcnManagementService; + +/** + * VcnManagementService manages Virtual Carrier Network profiles and lifecycles. + * + *
The internal structure of the VCN Management subsystem is as follows:
+ *
+ * +------------------------+ 1:1                                 +--------------------------------+
+ * |  VcnManagementService  | ------------ Creates -------------> |  TelephonySubscriptionManager  |
+ * |                        |                                     |                                |
+ * | Manages configs and    |                                     | Tracks subscriptions, carrier  |
+ * | VcnInstance lifecycles | <--- Notifies of subscription & --- | privilege changes, caches maps |
+ * +------------------------+      carrier privilege changes      +--------------------------------+
+ *      | 1:N          ^
+ *      |              |
+ *      |              +-------------------------------+
+ *      +---------------+                              |
+ *                      |                              |
+ *         Creates when config present,                |
+ *        subscription group active, and               |
+ *      providing app is carrier privileged     Notifies of safe
+ *                      |                      mode state changes
+ *                      v                              |
+ * +-----------------------------------------------------------------------+
+ * |                              VcnInstance                              |
+ * |                                                                       |
+ * |   Manages tunnel lifecycles based on fulfillable NetworkRequest(s)    |
+ * |                        and overall safe-mode                          |
+ * +-----------------------------------------------------------------------+
+ *                      | 1:N                          ^
+ *              Creates to fulfill                     |
+ *           NetworkRequest(s), tears        Notifies of VcnTunnel
+ *          down when no longer needed   teardown (e.g. Network reaped)
+ *                      |                 and safe-mode timer changes
+ *                      v                              |
+ * +-----------------------------------------------------------------------+
+ * |                               VcnTunnel                               |
+ * |                                                                       |
+ * |       Manages a single (IKEv2) tunnel session and NetworkAgent,       |
+ * |  handles mobility events, (IPsec) Tunnel setup and safe-mode timers   |
+ * +-----------------------------------------------------------------------+
+ *                      | 1:1                          ^
+ *                      |                              |
+ *          Creates upon instantiation      Notifies of changes in
+ *                      |                 selected underlying network
+ *                      |                     or its properties
+ *                      v                              |
+ * +-----------------------------------------------------------------------+
+ * |                       UnderlyingNetworkTracker                        |
+ * |                                                                       |
+ * | Manages lifecycle of underlying physical networks, filing requests to |
+ * | bring them up, and releasing them as they become no longer necessary  |
+ * +-----------------------------------------------------------------------+
+ * 
+ * + * @hide + */ +public class VcnManagementService extends IVcnManagementService.Stub { + @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + + public static final boolean VDBG = false; // STOPSHIP: if true + + /* Binder context for this service */ + @NonNull private final Context mContext; + @NonNull private final Dependencies mDeps; + + private VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { + mContext = requireNonNull(context, "Missing context"); + mDeps = requireNonNull(deps, "Missing dependencies"); + } + + // Package-visibility for SystemServer to create instances. + static VcnManagementService create(@NonNull Context context) { + return new VcnManagementService(context, new Dependencies()); + } + + private static class Dependencies {} + + /** Notifies the VcnManagementService that external dependencies can be set up */ + public void systemReady() {} +} From 0d1e88e46529283aaf39415e50e920abb8922d9f Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Oct 2020 18:30:50 -0700 Subject: [PATCH 0005/1057] Add test mapping and setup tests for VCN This change adds the necessary files for the VCN tests to be run using atest. Bug: 163431877 Test: atest FrameworksVcnTests Change-Id: Ib9a91189bae38170a9fb37d420e262b023534b4b --- Vcn/tests/unit/Android.bp | 27 +++++++++++++++++++++++++++ Vcn/tests/unit/AndroidManifest.xml | 28 ++++++++++++++++++++++++++++ Vcn/tests/unit/AndroidTest.xml | 28 ++++++++++++++++++++++++++++ Vcn/tests/unit/TEST_MAPPING | 7 +++++++ 4 files changed, 90 insertions(+) create mode 100644 Vcn/tests/unit/Android.bp create mode 100644 Vcn/tests/unit/AndroidManifest.xml create mode 100644 Vcn/tests/unit/AndroidTest.xml create mode 100644 Vcn/tests/unit/TEST_MAPPING diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp new file mode 100644 index 0000000000..f967bf0d8f --- /dev/null +++ b/Vcn/tests/unit/Android.bp @@ -0,0 +1,27 @@ +//######################################################################## +// Build FrameworksVcnTests package +//######################################################################## + +android_test { + name: "FrameworksVcnTests", + srcs: [ + "java/**/*.java", + "java/**/*.kt", + ], + platform_apis: true, + test_suites: ["device-tests"], + certificate: "platform", + static_libs: [ + "androidx.test.rules", + "frameworks-base-testutils", + "framework-protos", + "mockito-target-minus-junit4", + "platform-test-annotations", + "services.core", + ], + libs: [ + "android.test.runner", + "android.test.base", + "android.test.mock", + ], +} diff --git a/Vcn/tests/unit/AndroidManifest.xml b/Vcn/tests/unit/AndroidManifest.xml new file mode 100644 index 0000000000..2ad9aac670 --- /dev/null +++ b/Vcn/tests/unit/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/Vcn/tests/unit/AndroidTest.xml b/Vcn/tests/unit/AndroidTest.xml new file mode 100644 index 0000000000..dc521fd7bc --- /dev/null +++ b/Vcn/tests/unit/AndroidTest.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/Vcn/tests/unit/TEST_MAPPING b/Vcn/tests/unit/TEST_MAPPING new file mode 100644 index 0000000000..54fa411e35 --- /dev/null +++ b/Vcn/tests/unit/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "FrameworksVcnTests" + } + ] +} \ No newline at end of file From 68fb8cfc465046a746d38551c3173a94c6673c54 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 6 Nov 2020 14:53:28 -0800 Subject: [PATCH 0006/1057] Add utilities to persist lists of Persistable objects This change adds a utility class to enable persistance of Lists of objects. The PersistableBundle class does not currently support lists or arrays of PersistableBundles, presumably due to the potential for key conflicts. The utility classes added here avoid that concern by nesting all lists as separate persistable bundles. Bug: 163594033 Test: New PersistableBundleUtilsTest added, passing Change-Id: I89478cf0d05d41a4b0d769de4859421061a1f1d9 --- .../net/vcn/util/PersistableBundleUtils.java | 105 ++++++++++++++ .../vcn/util/PersistableBundleUtilsTest.java | 131 ++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java new file mode 100644 index 0000000000..73054ce046 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -0,0 +1,105 @@ +/* + * 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.vcn.util; + +import android.annotation.NonNull; +import android.os.PersistableBundle; + +import java.util.ArrayList; +import java.util.List; + +/** @hide */ +public class PersistableBundleUtils { + private static final String LIST_KEY_FORMAT = "LIST_ITEM_%d"; + private static final String LIST_LENGTH_KEY = "LIST_LENGTH"; + + /** + * Functional interface to convert an object of the specified type to a PersistableBundle. + * + * @param the type of the source object + */ + public interface Serializer { + /** + * Converts this object to a PersistableBundle. + * + * @return the PersistableBundle representation of this object + */ + PersistableBundle toPersistableBundle(T obj); + } + + /** + * Functional interface used to create an object of the specified type from a PersistableBundle. + * + * @param the type of the resultant object + */ + public interface Deserializer { + /** + * Creates an instance of specified type from a PersistableBundle representation. + * + * @param in the PersistableBundle representation + * @return an instance of the specified type + */ + T fromPersistableBundle(PersistableBundle in); + } + + /** + * Converts from a list of Persistable objects to a single PersistableBundle. + * + *

To avoid key collisions, NO additional key/value pairs should be added to the returned + * PersistableBundle object. + * + * @param the type of the objects to convert to the PersistableBundle + * @param in the list of objects to be serialized into a PersistableBundle + * @param serializer an implementation of the {@link Serializer} functional interface that + * converts an object of type T to a PersistableBundle + */ + @NonNull + public static PersistableBundle fromList( + @NonNull List in, @NonNull Serializer serializer) { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(LIST_LENGTH_KEY, in.size()); + for (int i = 0; i < in.size(); i++) { + final String key = String.format(LIST_KEY_FORMAT, i); + result.putPersistableBundle(key, serializer.toPersistableBundle(in.get(i))); + } + return result; + } + + /** + * Converts from a PersistableBundle to a list of objects. + * + * @param the type of the objects to convert from a PersistableBundle + * @param in the PersistableBundle containing the persisted list + * @param deserializer an implementation of the {@link Deserializer} functional interface that + * builds the relevant type of objects. + */ + @NonNull + public static List toList( + @NonNull PersistableBundle in, @NonNull Deserializer deserializer) { + final int listLength = in.getInt(LIST_LENGTH_KEY); + final ArrayList result = new ArrayList<>(listLength); + + for (int i = 0; i < listLength; i++) { + final String key = String.format(LIST_KEY_FORMAT, i); + final PersistableBundle item = in.getPersistableBundle(key); + + result.add(deserializer.fromPersistableBundle(item)); + } + return result; + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java new file mode 100644 index 0000000000..f78eeb69b5 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.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.server.vcn.util; + +import static org.junit.Assert.assertEquals; + +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PersistableBundleUtilsTest { + private static final String TEST_KEY = "testKey"; + private static final String TEST_STRING_PREFIX = "testString"; + private static final int[] TEST_INT_ARRAY = new int[] {0, 1, 2, 3, 4}; + + private static final int NUM_COLLECTION_ENTRIES = 10; + + private static class TestClass { + private static final String TEST_INTEGER_KEY = "mTestInteger"; + private final int mTestInteger; + + private static final String TEST_INT_ARRAY_KEY = "mTestIntArray"; + private final int[] mTestIntArray; + + private static final String TEST_STRING_KEY = "mTestString"; + private final String mTestString; + + private static final String TEST_PERSISTABLE_BUNDLE_KEY = "mTestPersistableBundle"; + private final PersistableBundle mTestPersistableBundle; + + TestClass( + int testInteger, + int[] testIntArray, + String testString, + PersistableBundle testPersistableBundle) { + mTestInteger = testInteger; + mTestIntArray = testIntArray; + mTestString = testString; + mTestPersistableBundle = testPersistableBundle; + } + + TestClass(PersistableBundle in) { + mTestInteger = in.getInt(TEST_INTEGER_KEY); + mTestIntArray = in.getIntArray(TEST_INT_ARRAY_KEY); + mTestString = in.getString(TEST_STRING_KEY); + mTestPersistableBundle = in.getPersistableBundle(TEST_PERSISTABLE_BUNDLE_KEY); + } + + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(TEST_INTEGER_KEY, mTestInteger); + result.putIntArray(TEST_INT_ARRAY_KEY, mTestIntArray); + result.putString(TEST_STRING_KEY, mTestString); + result.putPersistableBundle(TEST_PERSISTABLE_BUNDLE_KEY, mTestPersistableBundle); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash( + mTestInteger, + Arrays.hashCode(mTestIntArray), + mTestString, + mTestPersistableBundle); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof TestClass)) { + return false; + } + + final TestClass other = (TestClass) o; + + // TODO: Add a proper equals() to PersistableBundle. But in the meantime, force + // TODO: unparcelling in order to allow test comparison. + if (mTestPersistableBundle.size() != other.mTestPersistableBundle.size()) { + return false; + } + + return mTestInteger == other.mTestInteger + && Arrays.equals(mTestIntArray, other.mTestIntArray) + && mTestString.equals(other.mTestString) + && mTestPersistableBundle.kindofEquals(other.mTestPersistableBundle); + } + } + + @Test + public void testConversionLossless() throws Exception { + final List sourceList = new ArrayList<>(); + for (int i = 0; i < NUM_COLLECTION_ENTRIES; i++) { + final PersistableBundle innerBundle = new PersistableBundle(); + innerBundle.putInt(TEST_KEY, i); + + sourceList.add(new TestClass(i, TEST_INT_ARRAY, TEST_STRING_PREFIX + i, innerBundle)); + } + + final PersistableBundle bundled = + PersistableBundleUtils.fromList(sourceList, TestClass::toPersistableBundle); + final List resultList = PersistableBundleUtils.toList(bundled, TestClass::new); + + assertEquals(sourceList, resultList); + } +} From 74a59914745b251407ce245188f53a302c77952a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 6 Nov 2020 21:43:58 -0800 Subject: [PATCH 0007/1057] Add utils for converting Maps and ParcelUuid to/from PersistableBundle This commit expands the PersistableBundleUtils by adding maps. LinkedHashMap is used in an attempt to preserve ordering where stability is important. Similarly, this commit adds the ability to persist ParcelUuid(s) via conversion to Strings. This commit also adds a helper method to safely read and write to and from disk Bug: 163611304 Test: New tests added, passing Change-Id: Ife24e94006445007be68ab0e03f27b2fd5643aa2 --- .../net/vcn/util/PersistableBundleUtils.java | 186 +++++++++++++++++- .../vcn/util/PersistableBundleUtilsTest.java | 63 +++++- 2 files changed, 245 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 73054ce046..7d276c7976 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -17,15 +17,31 @@ package com.android.server.vcn.util; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.ParcelUuid; import android.os.PersistableBundle; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** @hide */ public class PersistableBundleUtils { private static final String LIST_KEY_FORMAT = "LIST_ITEM_%d"; - private static final String LIST_LENGTH_KEY = "LIST_LENGTH"; + private static final String COLLECTION_SIZE_KEY = "COLLECTION_LENGTH"; + private static final String MAP_KEY_FORMAT = "MAP_KEY_%d"; + private static final String MAP_VALUE_FORMAT = "MAP_VALUE_%d"; + + private static final String PARCEL_UUID_KEY = "PARCEL_UUID"; /** * Functional interface to convert an object of the specified type to a PersistableBundle. @@ -56,6 +72,33 @@ public class PersistableBundleUtils { T fromPersistableBundle(PersistableBundle in); } + /** + * Converts a ParcelUuid to a PersistableBundle. + * + *

To avoid key collisions, NO additional key/value pairs should be added to the returned + * PersistableBundle object. + * + * @param uuid a ParcelUuid instance to persist + * @return the PersistableBundle instance + */ + public static PersistableBundle fromParcelUuid(ParcelUuid uuid) { + final PersistableBundle result = new PersistableBundle(); + + result.putString(PARCEL_UUID_KEY, uuid.toString()); + + return result; + } + + /** + * Converts from a PersistableBundle to a ParcelUuid. + * + * @param bundle the PersistableBundle containing the ParcelUuid + * @return the ParcelUuid instance + */ + public static ParcelUuid toParcelUuid(PersistableBundle bundle) { + return ParcelUuid.fromString(bundle.getString(PARCEL_UUID_KEY)); + } + /** * Converts from a list of Persistable objects to a single PersistableBundle. * @@ -72,7 +115,7 @@ public class PersistableBundleUtils { @NonNull List in, @NonNull Serializer serializer) { final PersistableBundle result = new PersistableBundle(); - result.putInt(LIST_LENGTH_KEY, in.size()); + result.putInt(COLLECTION_SIZE_KEY, in.size()); for (int i = 0; i < in.size(); i++) { final String key = String.format(LIST_KEY_FORMAT, i); result.putPersistableBundle(key, serializer.toPersistableBundle(in.get(i))); @@ -91,7 +134,7 @@ public class PersistableBundleUtils { @NonNull public static List toList( @NonNull PersistableBundle in, @NonNull Deserializer deserializer) { - final int listLength = in.getInt(LIST_LENGTH_KEY); + final int listLength = in.getInt(COLLECTION_SIZE_KEY); final ArrayList result = new ArrayList<>(listLength); for (int i = 0; i < listLength; i++) { @@ -102,4 +145,141 @@ public class PersistableBundleUtils { } return result; } + + /** + * Converts from a Map of Persistable objects to a single PersistableBundle. + * + *

To avoid key collisions, NO additional key/value pairs should be added to the returned + * PersistableBundle object. + * + * @param the type of the map-key to convert to the PersistableBundle + * @param the type of the map-value to convert to the PersistableBundle + * @param in the Map of objects implementing the {@link Persistable} interface + * @param keySerializer an implementation of the {@link Serializer} functional interface that + * converts a map-key of type T to a PersistableBundle + * @param valueSerializer an implementation of the {@link Serializer} functional interface that + * converts a map-value of type E to a PersistableBundle + */ + @NonNull + public static PersistableBundle fromMap( + @NonNull Map in, + @NonNull Serializer keySerializer, + @NonNull Serializer valueSerializer) { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(COLLECTION_SIZE_KEY, in.size()); + int i = 0; + for (Entry entry : in.entrySet()) { + final String keyKey = String.format(MAP_KEY_FORMAT, i); + final String valueKey = String.format(MAP_VALUE_FORMAT, i); + result.putPersistableBundle(keyKey, keySerializer.toPersistableBundle(entry.getKey())); + result.putPersistableBundle( + valueKey, valueSerializer.toPersistableBundle(entry.getValue())); + + i++; + } + + return result; + } + + /** + * Converts from a PersistableBundle to a Map of objects. + * + *

In an attempt to preserve ordering, the returned map will be a LinkedHashMap. However, the + * guarantees on the ordering can only ever be as strong as the map that was serialized in + * {@link fromMap()}. If the initial map that was serialized had no ordering guarantees, the + * deserialized map similarly may be of a non-deterministic order. + * + * @param the type of the map-key to convert from a PersistableBundle + * @param the type of the map-value to convert from a PersistableBundle + * @param in the PersistableBundle containing the persisted Map + * @param keyDeserializer an implementation of the {@link Deserializer} functional interface + * that builds the relevant type of map-key. + * @param valueDeserializer an implementation of the {@link Deserializer} functional interface + * that builds the relevant type of map-value. + * @return An instance of the parsed map as a LinkedHashMap (in an attempt to preserve + * ordering). + */ + @NonNull + public static LinkedHashMap toMap( + @NonNull PersistableBundle in, + @NonNull Deserializer keyDeserializer, + @NonNull Deserializer valueDeserializer) { + final int mapSize = in.getInt(COLLECTION_SIZE_KEY); + final LinkedHashMap result = new LinkedHashMap<>(mapSize); + + for (int i = 0; i < mapSize; i++) { + final String keyKey = String.format(MAP_KEY_FORMAT, i); + final String valueKey = String.format(MAP_VALUE_FORMAT, i); + final PersistableBundle keyBundle = in.getPersistableBundle(keyKey); + final PersistableBundle valueBundle = in.getPersistableBundle(valueKey); + + final K key = keyDeserializer.fromPersistableBundle(keyBundle); + final V value = valueDeserializer.fromPersistableBundle(valueBundle); + result.put(key, value); + } + return result; + } + + /** + * Ensures safe reading and writing of {@link PersistableBundle}s to and from disk. + * + *

This class will enforce exclusion between reads and writes using the standard semantics of + * a ReadWriteLock. Specifically, concurrent readers ARE allowed, but reads/writes from/to the + * file are mutually exclusive. In other words, for an unbounded number n, the acceptable states + * are n readers, OR 1 writer (but not both). + */ + public static class LockingReadWriteHelper { + private final ReadWriteLock mDiskLock = new ReentrantReadWriteLock(); + private final String mPath; + + public LockingReadWriteHelper(@NonNull String path) { + mPath = Objects.requireNonNull(path, "fileName was null"); + } + + /** + * Reads the {@link PersistableBundle} from the disk. + * + * @return the PersistableBundle, if the file existed, or null otherwise + */ + @Nullable + public PersistableBundle readFromDisk() throws IOException { + try { + mDiskLock.readLock().lock(); + final File file = new File(mPath); + if (!file.exists()) { + return null; + } + + try (FileInputStream fis = new FileInputStream(file)) { + return PersistableBundle.readFromStream(fis); + } + } finally { + mDiskLock.readLock().unlock(); + } + } + + /** + * Writes a {@link PersistableBundle} to disk. + * + * @param bundle the {@link PersistableBundle} to write to disk + */ + public void writeToDisk(@NonNull PersistableBundle bundle) throws IOException { + Objects.requireNonNull(bundle, "bundle was null"); + + try { + mDiskLock.writeLock().lock(); + final File file = new File(mPath); + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + + try (FileOutputStream fos = new FileOutputStream(file)) { + bundle.writeToStream(fos); + } + } finally { + mDiskLock.writeLock().unlock(); + } + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index f78eeb69b5..07d3049ab6 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -28,6 +28,7 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; @@ -40,6 +41,43 @@ public class PersistableBundleUtilsTest { private static final int NUM_COLLECTION_ENTRIES = 10; + private static class TestKey { + private static final String TEST_INTEGER_KEY = + "mTestInteger"; // Purposely colliding with keys of test class to ensure namespacing + private final int mTestInteger; + + TestKey(int testInteger) { + mTestInteger = testInteger; + } + + TestKey(PersistableBundle in) { + mTestInteger = in.getInt(TEST_INTEGER_KEY); + } + + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(TEST_INTEGER_KEY, mTestInteger); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash(mTestInteger); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof TestKey)) { + return false; + } + + final TestKey other = (TestKey) o; + return mTestInteger == other.mTestInteger; + } + } + private static class TestClass { private static final String TEST_INTEGER_KEY = "mTestInteger"; private final int mTestInteger; @@ -113,7 +151,7 @@ public class PersistableBundleUtilsTest { } @Test - public void testConversionLossless() throws Exception { + public void testListConversionLossless() throws Exception { final List sourceList = new ArrayList<>(); for (int i = 0; i < NUM_COLLECTION_ENTRIES; i++) { final PersistableBundle innerBundle = new PersistableBundle(); @@ -128,4 +166,27 @@ public class PersistableBundleUtilsTest { assertEquals(sourceList, resultList); } + + @Test + public void testMapConversionLossless() throws Exception { + final LinkedHashMap sourceMap = new LinkedHashMap<>(); + for (int i = 0; i < NUM_COLLECTION_ENTRIES; i++) { + final TestKey key = new TestKey(i * i); + + final PersistableBundle innerBundle = new PersistableBundle(); + innerBundle.putInt(TEST_KEY, i); + final TestClass value = + new TestClass(i, TEST_INT_ARRAY, TEST_STRING_PREFIX + i, innerBundle); + + sourceMap.put(key, value); + } + + final PersistableBundle bundled = + PersistableBundleUtils.fromMap( + sourceMap, TestKey::toPersistableBundle, TestClass::toPersistableBundle); + final LinkedHashMap resultList = + PersistableBundleUtils.toMap(bundled, TestKey::new, TestClass::new); + + assertEquals(sourceMap, resultList); + } } From 6c764f9d7b56ee8c583aab577b19116b38cea792 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 9 Nov 2020 10:45:04 -0800 Subject: [PATCH 0008/1057] Support converting byte array to/from PersistableBundle Test: FrameworksVcnTests:PersistableBundleUtilsTest(new tests added) Change-Id: I1d700c9b6d10a40ef43abcab449d4b07d897f0ec --- .../net/vcn/util/PersistableBundleUtils.java | 40 +++++++++++++++++++ .../vcn/util/PersistableBundleUtilsTest.java | 11 +++++ 2 files changed, 51 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 7d276c7976..3672f9a246 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import android.os.ParcelUuid; import android.os.PersistableBundle; +import com.android.internal.util.HexDump; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -42,6 +44,7 @@ public class PersistableBundleUtils { private static final String MAP_VALUE_FORMAT = "MAP_VALUE_%d"; private static final String PARCEL_UUID_KEY = "PARCEL_UUID"; + private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY"; /** * Functional interface to convert an object of the specified type to a PersistableBundle. @@ -146,6 +149,43 @@ public class PersistableBundleUtils { return result; } + // TODO: b/170513329 Delete #fromByteArray and #toByteArray once BaseBundle#putByteArray and + // BaseBundle#getByteArray are exposed. + + /** + * Converts a byte array to a PersistableBundle. + * + *

To avoid key collisions, NO additional key/value pairs should be added to the returned + * PersistableBundle object. + * + * @param array a byte array instance to persist + * @return the PersistableBundle instance + */ + public static PersistableBundle fromByteArray(byte[] array) { + final PersistableBundle result = new PersistableBundle(); + + result.putString(BYTE_ARRAY_KEY, HexDump.toHexString(array)); + + return result; + } + + /** + * Converts from a PersistableBundle to a byte array. + * + * @param bundle the PersistableBundle containing the byte array + * @return the byte array instance + */ + public static byte[] toByteArray(PersistableBundle bundle) { + Objects.requireNonNull(bundle, "PersistableBundle is null"); + + String hex = bundle.getString(BYTE_ARRAY_KEY); + if (hex == null || hex.length() % 2 != 0) { + throw new IllegalArgumentException("PersistableBundle contains invalid byte array"); + } + + return HexDump.hexStringToByteArray(hex); + } + /** * Converts from a Map of Persistable objects to a single PersistableBundle. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index 07d3049ab6..4d8424bc87 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn.util; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.os.PersistableBundle; @@ -189,4 +190,14 @@ public class PersistableBundleUtilsTest { assertEquals(sourceMap, resultList); } + + @Test + public void testByteArrayConversionLossless() { + final byte[] byteArray = "testByteArrayConversionLossless".getBytes(); + + PersistableBundle bundle = PersistableBundleUtils.fromByteArray(byteArray); + byte[] result = PersistableBundleUtils.toByteArray(bundle); + + assertArrayEquals(byteArray, result); + } } From 1634f7372670994f05894fd63913550a7518aa05 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 10 Sep 2020 12:09:17 -0700 Subject: [PATCH 0009/1057] Support converting integer to/from PersistableBundle This CL is for facilitating converting Map and List that contains integer type objects. Bug: 163604823 Test: PersistableBundleUtilsTest(new tests added) Change-Id: I24239caf70035e19c3fb5eb4a85b6a0c6ccadb5a --- .../net/vcn/util/PersistableBundleUtils.java | 16 ++++++++++++++++ .../vcn/util/PersistableBundleUtilsTest.java | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 3672f9a246..5c1b5ffb22 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -45,6 +45,7 @@ public class PersistableBundleUtils { private static final String PARCEL_UUID_KEY = "PARCEL_UUID"; private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY"; + private static final String INTEGER_KEY = "INTEGER_KEY"; /** * Functional interface to convert an object of the specified type to a PersistableBundle. @@ -75,6 +76,21 @@ public class PersistableBundleUtils { T fromPersistableBundle(PersistableBundle in); } + /** Serializer to convert an integer to a PersistableBundle. */ + public static final Serializer INTEGER_SERIALIZER = + (i) -> { + final PersistableBundle result = new PersistableBundle(); + result.putInt(INTEGER_KEY, i); + return result; + }; + + /** Deserializer to convert a PersistableBundle to an integer. */ + public static final Deserializer INTEGER_DESERIALIZER = + (bundle) -> { + Objects.requireNonNull(bundle, "PersistableBundle is null"); + return bundle.getInt(INTEGER_KEY); + }; + /** * Converts a ParcelUuid to a PersistableBundle. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index 4d8424bc87..a44a734a2d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -200,4 +200,15 @@ public class PersistableBundleUtilsTest { assertArrayEquals(byteArray, result); } + + @Test + public void testIntegerConversionLossless() throws Exception { + final int testInt = 1; + final PersistableBundle integerBundle = + PersistableBundleUtils.INTEGER_SERIALIZER.toPersistableBundle(testInt); + final int result = + PersistableBundleUtils.INTEGER_DESERIALIZER.fromPersistableBundle(integerBundle); + + assertEquals(testInt, result); + } } From a4b59082c8bec7adcbfa742e03f95d6e1885732b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 4 Aug 2020 11:51:17 -0700 Subject: [PATCH 0010/1057] Add stubs for VCN configuration management This change adds stubs for both the API and the internal binder interfaces. Bug: 163431877 Test: Compiles, boots Change-Id: I11183d9fe3ad53944882b163eee5110e85898393 --- .../net/vcn/IVcnManagementService.aidl | 5 ++ .../src/android/net/vcn/VcnConfig.aidl | 20 +++++ .../src/android/net/vcn/VcnConfig.java | 83 +++++++++++++++++++ .../src/android/net/vcn/VcnManager.java | 57 ++++++++++++- .../android/server/VcnManagementService.java | 33 +++++++- 5 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnConfig.aidl create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnConfig.java diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index af06906ca2..9dd01140b4 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -16,8 +16,13 @@ package android.net.vcn; +import android.net.vcn.VcnConfig; +import android.os.ParcelUuid; + /** * @hide */ interface IVcnManagementService { + void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config); + void clearVcnConfig(in ParcelUuid subscriptionGroup); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.aidl b/Vcn/framework-b/src/android/net/vcn/VcnConfig.aidl new file mode 100644 index 0000000000..67006a42a7 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.aidl @@ -0,0 +1,20 @@ +/* + * 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.vcn; + +/** @hide */ +parcelable VcnConfig; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java new file mode 100644 index 0000000000..148acf1308 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.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.vcn; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class represents a configuration for a Virtual Carrier Network. + * + * @hide + */ +public final class VcnConfig implements Parcelable { + @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); + + private VcnConfig() { + validate(); + } + // TODO: Implement getters, validators, etc + + /** + * Validates this configuration. + * + * @hide + */ + private void validate() { + // TODO: implement validation logic + } + + // Parcelable methods + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) {} + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @NonNull + public VcnConfig createFromParcel(Parcel in) { + // TODO: Ensure all methods are pulled from the parcels + return new VcnConfig(); + } + + @NonNull + public VcnConfig[] newArray(int size) { + return new VcnConfig[size]; + } + }; + + /** This class is used to incrementally build {@link VcnConfig} objects. */ + public static class Builder { + // TODO: Implement this builder + + /** + * Builds and validates the VcnConfig. + * + * @return an immutable VcnConfig instance + */ + @NonNull + public VcnConfig build() { + return new VcnConfig(); + } + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index d563b03501..6769b9e46e 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -18,11 +18,14 @@ package android.net.vcn; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; +import android.os.ParcelUuid; +import android.os.RemoteException; /** - * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks + * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. * * @hide */ @@ -45,4 +48,56 @@ public final class VcnManager { mContext = requireNonNull(ctx, "missing context"); mService = requireNonNull(service, "missing service"); } + + // TODO: Make setVcnConfig(), clearVcnConfig() Public API + /** + * Sets the VCN configuration for a given subscription group. + * + *

An app that has carrier privileges for any of the subscriptions in the given group may set + * a VCN configuration. If a configuration already exists for the given subscription group, it + * will be overridden. Any active VCN(s) may be forced to restart to use the new configuration. + * + *

This API is ONLY permitted for callers running as the primary user. + * + * @param subscriptionGroup the subscription group that the configuration should be applied to + * @param config the configuration parameters for the VCN + * @throws SecurityException if the caller does not have carrier privileges, or is not running + * as the primary user + * @hide + */ + @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant + public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + requireNonNull(config, "config was null"); + + try { + mService.setVcnConfig(subscriptionGroup, config); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + // TODO: Make setVcnConfig(), clearVcnConfig() Public API + /** + * Clears the VCN configuration for a given subscription group. + * + *

An app that has carrier privileges for any of the subscriptions in the given group may + * clear a VCN configuration. This API is ONLY permitted for callers running as the primary + * user. Any active VCN will be torn down. + * + * @param subscriptionGroup the subscription group that the configuration should be applied to + * @throws SecurityException if the caller does not have carrier privileges, or is not running + * as the primary user + * @hide + */ + @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant + public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { + requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + + try { + mService.clearVcnConfig(subscriptionGroup); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index db7e16ca8b..8ddcfc83ba 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -21,6 +21,8 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.content.Context; import android.net.vcn.IVcnManagementService; +import android.net.vcn.VcnConfig; +import android.os.ParcelUuid; /** * VcnManagementService manages Virtual Carrier Network profiles and lifecycles. @@ -98,6 +100,33 @@ public class VcnManagementService extends IVcnManagementService.Stub { private static class Dependencies {} - /** Notifies the VcnManagementService that external dependencies can be set up */ - public void systemReady() {} + /** Notifies the VcnManagementService that external dependencies can be set up. */ + public void systemReady() { + // TODO: Retrieve existing profiles from KeyStore + } + + /** + * Sets a VCN config for a given subscription group. + * + *

Implements the IVcnManagementService Binder interface. + */ + @Override + public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + requireNonNull(config, "config was null"); + + // TODO: Store VCN configuration, trigger startup as necessary + } + + /** + * Clears the VcnManagementService for a given subscription group. + * + *

Implements the IVcnManagementService Binder interface. + */ + @Override + public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { + requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + + // TODO: Clear VCN configuration, trigger teardown as necessary + } } From a474e4ee1f52e4711b11c6963c52077a8630fc87 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 5 Aug 2020 14:40:31 -0700 Subject: [PATCH 0011/1057] Add NetworkProvider to VcnManagementService This change adds a skeleton VcnNetworkProvider, and registers it with ConnectivityService upon system startup. Bug: 163431879 Test: FrameworksVcnTests passing Change-Id: I7720db1cea805cbdca052a2e37cb2d754189ea05 --- .../android/server/VcnManagementService.java | 51 ++++++++++++++- .../server/VcnManagementServiceTest.java | 62 +++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 8ddcfc83ba..f376473bb2 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -20,10 +20,18 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkProvider; +import android.net.NetworkRequest; import android.net.vcn.IVcnManagementService; import android.net.vcn.VcnConfig; +import android.os.HandlerThread; +import android.os.Looper; import android.os.ParcelUuid; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + /** * VcnManagementService manages Virtual Carrier Network profiles and lifecycles. * @@ -88,9 +96,16 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; - private VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { + @NonNull private final Looper mLooper; + @NonNull private final VcnNetworkProvider mNetworkProvider; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { mContext = requireNonNull(context, "Missing context"); mDeps = requireNonNull(deps, "Missing dependencies"); + + mLooper = mDeps.getLooper(); + mNetworkProvider = new VcnNetworkProvider(mContext, mLooper); } // Package-visibility for SystemServer to create instances. @@ -98,11 +113,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { return new VcnManagementService(context, new Dependencies()); } - private static class Dependencies {} + /** External dependencies used by VcnManagementService, for injection in tests */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + private HandlerThread mHandlerThread; + + /** Retrieves a looper for the VcnManagementService */ + public Looper getLooper() { + if (mHandlerThread == null) { + synchronized (this) { + if (mHandlerThread == null) { + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + } + } + } + return mHandlerThread.getLooper(); + } + } /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { // TODO: Retrieve existing profiles from KeyStore + + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkProvider(mNetworkProvider); } /** @@ -129,4 +164,16 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO: Clear VCN configuration, trigger teardown as necessary } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + class VcnNetworkProvider extends NetworkProvider { + VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { + super(context, looper, VcnNetworkProvider.class.getSimpleName()); + } + + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + // TODO: Handle network requests - Ensure VCN started, and start appropriate tunnels. + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java new file mode 100644 index 0000000000..c91fdbffd7 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -0,0 +1,62 @@ +/* + * 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; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link VcnManagementService}. */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnManagementServiceTest { + private final Context mMockContext = mock(Context.class); + private final VcnManagementService.Dependencies mMockDeps = + mock(VcnManagementService.Dependencies.class); + private final TestLooper mTestLooper = new TestLooper(); + private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class); + private final VcnManagementService mVcnMgmtSvc; + + public VcnManagementServiceTest() { + doReturn(Context.CONNECTIVITY_SERVICE) + .when(mMockContext) + .getSystemServiceName(ConnectivityManager.class); + doReturn(mConnMgr).when(mMockContext).getSystemService(Context.CONNECTIVITY_SERVICE); + + doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper(); + mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + } + + @Test + public void testSystemReady() throws Exception { + mVcnMgmtSvc.systemReady(); + + verify(mConnMgr) + .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class)); + } +} From 1d32d775ff2405c88b2de302d35ea29006e850aa Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 19 Aug 2020 16:17:20 -0700 Subject: [PATCH 0012/1057] Add VcnContext, Vcn skeletons This change adds the Vcn class, which represents a single carrier, single-subscription-group abstraction of the Network. Additionally, this adds a VCN context, which encapsulates context, looper and network providers to ensure all instances uses the same context, looper and network provider. Bug: 163432852 Test: atest FrameworksVcnTests Change-Id: I19ecdb4b406102e571029b5520a1ff028bfa1064 --- .../android/server/VcnManagementService.java | 10 +- .../src/com/android/server/vcn/Vcn.java | 95 +++++++++++++++++++ .../com/android/server/vcn/VcnContext.java | 60 ++++++++++++ 3 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/Vcn.java create mode 100644 Vcn/service-b/src/com/android/server/vcn/VcnContext.java diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f376473bb2..165b6a1b08 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -165,9 +165,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO: Clear VCN configuration, trigger teardown as necessary } - @VisibleForTesting(visibility = Visibility.PRIVATE) - class VcnNetworkProvider extends NetworkProvider { - VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { + /** + * Network provider for VCN networks. + * + * @hide + */ + public class VcnNetworkProvider extends NetworkProvider { + VcnNetworkProvider(Context context, Looper looper) { super(context, looper, VcnNetworkProvider.class.getSimpleName()); } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java new file mode 100644 index 0000000000..2af41726ca --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -0,0 +1,95 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.net.NetworkRequest; +import android.net.vcn.VcnConfig; +import android.os.Handler; +import android.os.Message; +import android.os.ParcelUuid; + +import java.util.Objects; + +/** + * Represents an single instance of a VCN. + * + *

Each Vcn instance manages all tunnels for a given subscription group, including per-capability + * networks, network selection, and multi-homing. + * + * @hide + */ +public class Vcn extends Handler { + private static final String TAG = Vcn.class.getSimpleName(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final ParcelUuid mSubscriptionGroup; + @NonNull private final Dependencies mDeps; + + @NonNull private VcnConfig mConfig; + + public Vcn( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull VcnConfig config) { + this(vcnContext, subscriptionGroup, config, new Dependencies()); + } + + private Vcn( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull VcnConfig config, + @NonNull Dependencies deps) { + super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); + mVcnContext = vcnContext; + mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mDeps = Objects.requireNonNull(deps, "Missing deps"); + + mConfig = Objects.requireNonNull(config, "Missing config"); + } + + /** Asynchronously updates the configuration and triggers a re-evaluation of Networks */ + public void updateConfig(@NonNull VcnConfig config) { + Objects.requireNonNull(config, "Missing config"); + // TODO: Proxy to handler, and make config there. + } + + /** Asynchronously tears down this Vcn instance, along with all tunnels and Networks */ + public void teardown() { + // TODO: Proxy to handler, and teardown there. + } + + /** Notifies this Vcn instance of a new NetworkRequest */ + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + Objects.requireNonNull(request, "Missing request"); + + // TODO: Proxy to handler, and handle there. + } + + @Override + public void handleMessage(@NonNull Message msg) { + // TODO: Do something + } + + /** Retrieves the network score for a VCN Network */ + private int getNetworkScore() { + // TODO: STOPSHIP: Make this use new NetworkSelection, or some magic "max in subGrp" value + return 52; + } + + private static class Dependencies {} +} diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java new file mode 100644 index 0000000000..8ab52931ca --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.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 com.android.server.vcn; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.Looper; + +import com.android.server.VcnManagementService.VcnNetworkProvider; + +import java.util.Objects; + +/** + * A simple class to pass around context information. + * + * @hide + */ +public class VcnContext { + @NonNull private final Context mContext; + @NonNull private final Looper mLooper; + @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + + public VcnContext( + @NonNull Context context, + @NonNull Looper looper, + @NonNull VcnNetworkProvider vcnNetworkProvider) { + mContext = Objects.requireNonNull(context, "Missing context"); + mLooper = Objects.requireNonNull(looper, "Missing looper"); + mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider"); + } + + @NonNull + public Context getContext() { + return mContext; + } + + @NonNull + public Looper getLooper() { + return mLooper; + } + + @NonNull + public VcnNetworkProvider getVcnNetworkProvider() { + return mVcnNetworkProvider; + } +} From d52e451131130deab220b4a823bad9ae0a0f9ded Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 17 Nov 2020 16:12:33 -0800 Subject: [PATCH 0013/1057] Add bug number to stopship comment for VCN Network scores Test: atest FrameworksVcnTests Change-Id: I7a637d39e7be2d59e53a1e3bd801c19b9163661d --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 2af41726ca..d51d16b1b4 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -87,7 +87,8 @@ public class Vcn extends Handler { /** Retrieves the network score for a VCN Network */ private int getNetworkScore() { - // TODO: STOPSHIP: Make this use new NetworkSelection, or some magic "max in subGrp" value + // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in + // subGrp" value return 52; } From 73736b56d81d4e574fdbc5569330328e2e024521 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 2 Sep 2020 18:50:04 -0700 Subject: [PATCH 0014/1057] Add VcnTunnel, UnderlyingNetworkTracker skeletons This change adds skeletons for each of the various major components used in the VCN. Additionally, this change adds the VcnGatewayConnectionConfig, used to configure each logical connection to the VCN gateway. Each VcnGatewayConnectionConfig specifies a Network that can be brought up on demand for a given telephony service (INTERNET, MMS, DUN, etc) Bug: 163602123 Bug: 163432852 Test: Skeletons only, no major testable pieces Change-Id: I7297690573c1b6ebd0ab9c1d434dd45c1e7d841d --- .../net/vcn/VcnGatewayConnectionConfig.java | 86 +++++++++++++++ .../server/vcn/UnderlyingNetworkTracker.java | 100 ++++++++++++++++++ .../server/vcn/VcnGatewayConnection.java | 84 +++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java create mode 100644 Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java create mode 100644 Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java new file mode 100644 index 0000000000..8160edc874 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -0,0 +1,86 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; + +/** + * This class represents a configuration for a connection to a Virtual Carrier Network gateway. + * + *

Each VcnGatewayConnectionConfig represents a single logical connection to a carrier gateway, + * and may provide one or more telephony services (as represented by network capabilities). Each + * gateway is expected to provide mobility for a given session as the device roams across {@link + * Network}s. + * + *

A VCN connection based on this configuration will be brought up dynamically based on device + * settings, and filed NetworkRequests. Underlying networks will be selected based on the services + * required by this configuration (as represented by network capabilities), and must be part of the + * subscription group under which this configuration is registered (see {@link + * VcnManager#setVcnConfig}). + * + *

Services that can be provided by a VCN network, or required for underlying networks are + * limited to services provided by cellular networks: + * + *

    + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_MMS} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_SUPL} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_DUN} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_FOTA} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_IMS} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_CBS} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_IA} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_RCS} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_XCAP} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_EIMS} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET} + *
  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX} + *
+ * + * @hide + */ +public final class VcnGatewayConnectionConfig { + private VcnGatewayConnectionConfig() { + validate(); + } + + // TODO: Implement getters, validators, etc + + /** + * Validates this configuration + * + * @hide + */ + private void validate() { + // TODO: implement validation logic + } + + // Parcelable methods + + /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects */ + public static class Builder { + // TODO: Implement this builder + + /** + * Builds and validates the VcnGatewayConnectionConfig + * + * @return an immutable VcnGatewayConnectionConfig instance + */ + @NonNull + public VcnGatewayConnectionConfig build() { + return new VcnGatewayConnectionConfig(); + } + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java new file mode 100644 index 0000000000..e1feb5aab8 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -0,0 +1,100 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.os.Handler; +import android.os.ParcelUuid; + +import java.util.Objects; + +/** + * Tracks a set of Networks underpinning a VcnGatewayConnection. + * + *

A single UnderlyingNetworkTracker is built to serve a SINGLE VCN Gateway Connection, and MUST + * be torn down with the VcnGatewayConnection in order to ensure underlying networks are allowed to + * be reaped. + * + * @hide + */ +public class UnderlyingNetworkTracker extends Handler { + @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final ParcelUuid mSubscriptionGroup; + @NonNull private final UnderlyingNetworkTrackerCallback mCb; + @NonNull private final Dependencies mDeps; + + public UnderlyingNetworkTracker( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull UnderlyingNetworkTrackerCallback cb) { + this(vcnContext, subscriptionGroup, cb, new Dependencies()); + } + + private UnderlyingNetworkTracker( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull UnderlyingNetworkTrackerCallback cb, + @NonNull Dependencies deps) { + super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); + mVcnContext = vcnContext; + mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mCb = Objects.requireNonNull(cb, "Missing cb"); + mDeps = Objects.requireNonNull(deps, "Missing deps"); + } + + /** Tears down this Tracker, and releases all underlying network requests. */ + public void teardown() {} + + /** An record of a single underlying network, caching relevant fields. */ + public static class UnderlyingNetworkRecord { + @NonNull public final Network network; + @NonNull public final NetworkCapabilities networkCapabilities; + @NonNull public final LinkProperties linkProperties; + public final boolean blocked; + + private UnderlyingNetworkRecord( + @NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, + boolean blocked) { + this.network = network; + this.networkCapabilities = networkCapabilities; + this.linkProperties = linkProperties; + this.blocked = blocked; + } + } + + /** Callbacks for being notified of the changes in, or to the selected underlying network. */ + public interface UnderlyingNetworkTrackerCallback { + /** + * Fired when a new underlying network is selected, or properties have changed. + * + *

This callback does NOT signal a mobility event. + * + * @param underlying The details of the new underlying network + */ + void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying); + } + + private static class Dependencies {} +} diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java new file mode 100644 index 0000000000..49c9b3297c --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -0,0 +1,84 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Handler; +import android.os.ParcelUuid; + +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; + +import java.util.Objects; + +/** + * A single VCN Gateway Connection, providing a single public-facing VCN network. + * + *

This class handles mobility events, performs retries, and tracks safe-mode conditions. + * + * @hide + */ +public class VcnGatewayConnection extends Handler implements UnderlyingNetworkTrackerCallback { + private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final ParcelUuid mSubscriptionGroup; + @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; + @NonNull private final Dependencies mDeps; + + public VcnGatewayConnection( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull VcnGatewayConnectionConfig connectionConfig) { + this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies()); + } + + private VcnGatewayConnection( + @NonNull VcnContext vcnContext, + @NonNull ParcelUuid subscriptionGroup, + @NonNull VcnGatewayConnectionConfig connectionConfig, + @NonNull Dependencies deps) { + super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); + mVcnContext = vcnContext; + mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); + mDeps = Objects.requireNonNull(deps, "Missing deps"); + + mUnderlyingNetworkTracker = + mDeps.newUnderlyingNetworkTracker(mVcnContext, subscriptionGroup, this); + } + + /** Tears down this GatewayConnection, and any resources used */ + public void teardown() { + mUnderlyingNetworkTracker.teardown(); + } + + private static class Dependencies { + public UnderlyingNetworkTracker newUnderlyingNetworkTracker( + VcnContext vcnContext, + ParcelUuid subscriptionGroup, + UnderlyingNetworkTrackerCallback callback) { + return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback); + } + } + + @Override + public void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying) {} +} From f3207c67ffdbda66899002eafa16df3641ccae52 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 19 Aug 2020 15:18:23 -0700 Subject: [PATCH 0015/1057] Enforce carrier privileges when setting/clearing VCN configs This change ensures that only carrier-privileged apps can modify VCN configs. Since carrier privilege is checked per-subId, we iterate through all subIds in the group, and check if any of them grant the calling app carrier privileges. Bug: 165670724 Test: New tests added, passing. Change-Id: Iac032136d9c1975e6b95a2d2ad9b811ce45c9a53 --- .../android/server/VcnManagementService.java | 73 ++++++++++ .../server/VcnManagementServiceTest.java | 135 +++++++++++++++++- 2 files changed, 203 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 165b6a1b08..e9f17fff5a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -25,13 +25,22 @@ import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.vcn.IVcnManagementService; import android.net.vcn.VcnConfig; +import android.os.Binder; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; +import android.os.Process; +import android.os.UserHandle; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import java.util.ArrayList; +import java.util.List; + /** * VcnManagementService manages Virtual Carrier Network profiles and lifecycles. * @@ -130,6 +139,18 @@ public class VcnManagementService extends IVcnManagementService.Stub { } return mHandlerThread.getLooper(); } + + /** + * Retrieves the caller's UID + * + *

This call MUST be made before calling {@link Binder#clearCallingIdentity}, otherwise + * this will not work properly. + * + * @return + */ + public int getBinderCallingUid() { + return Binder.getCallingUid(); + } } /** Notifies the VcnManagementService that external dependencies can be set up. */ @@ -140,6 +161,50 @@ public class VcnManagementService extends IVcnManagementService.Stub { .registerNetworkProvider(mNetworkProvider); } + private void enforcePrimaryUser() { + final int uid = mDeps.getBinderCallingUid(); + if (uid == Process.SYSTEM_UID) { + throw new IllegalStateException( + "Calling identity was System Server. Was Binder calling identity cleared?"); + } + + if (!UserHandle.getUserHandleForUid(uid).isSystem()) { + throw new SecurityException( + "VcnManagementService can only be used by callers running as the primary user"); + } + } + + private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) { + // Only apps running in the primary (system) user are allowed to configure the VCN. This is + // in line with Telephony's behavior with regards to binding to a Carrier App provided + // CarrierConfigService. + enforcePrimaryUser(); + + // TODO (b/172619301): Check based on events propagated from CarrierPrivilegesTracker + final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); + final List subscriptionInfos = new ArrayList<>(); + Binder.withCleanCallingIdentity( + () -> { + subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup)); + }); + + final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class); + for (SubscriptionInfo info : subscriptionInfos) { + // Check subscription is active first; much cheaper/faster check, and an app (currently) + // cannot be carrier privileged for inactive subscriptions. + if (subMgr.isValidSlotIndex(info.getSimSlotIndex()) + && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) { + // TODO (b/173717728): Allow configuration for inactive, but manageable + // subscriptions. + // TODO (b/173718661): Check for whole subscription groups at a time. + return; + } + } + + throw new SecurityException( + "Carrier privilege required for subscription group to set VCN Config"); + } + /** * Sets a VCN config for a given subscription group. * @@ -150,6 +215,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(config, "config was null"); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + + // TODO: Clear Binder calling identity + // TODO: Store VCN configuration, trigger startup as necessary } @@ -162,6 +231,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + + // TODO: Clear Binder calling identity + // TODO: Clear VCN configuration, trigger teardown as necessary } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index c91fdbffd7..633cf64bc2 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -16,14 +16,23 @@ package com.android.server; +import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.content.Context; import android.net.ConnectivityManager; +import android.net.vcn.VcnConfig; +import android.os.ParcelUuid; +import android.os.Process; +import android.os.UserHandle; import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -31,27 +40,73 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Collections; +import java.util.UUID; + /** Tests for {@link VcnManagementService}. */ @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); + private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO = + new SubscriptionInfo( + 1 /* id */, + "" /* iccId */, + 0 /* simSlotIndex */, + "Carrier" /* displayName */, + "Carrier" /* carrierName */, + 0 /* nameSource */, + 255 /* iconTint */, + "12345" /* number */, + 0 /* roaming */, + null /* icon */, + "0" /* mcc */, + "0" /* mnc */, + "0" /* countryIso */, + false /* isEmbedded */, + null /* nativeAccessRules */, + null /* cardString */, + false /* isOpportunistic */, + TEST_UUID_1.toString() /* groupUUID */, + 0 /* carrierId */, + 0 /* profileClass */); + private final Context mMockContext = mock(Context.class); private final VcnManagementService.Dependencies mMockDeps = mock(VcnManagementService.Dependencies.class); private final TestLooper mTestLooper = new TestLooper(); private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class); + private final TelephonyManager mTelMgr = mock(TelephonyManager.class); + private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class); private final VcnManagementService mVcnMgmtSvc; - public VcnManagementServiceTest() { - doReturn(Context.CONNECTIVITY_SERVICE) - .when(mMockContext) - .getSystemServiceName(ConnectivityManager.class); - doReturn(mConnMgr).when(mMockContext).getSystemService(Context.CONNECTIVITY_SERVICE); + public VcnManagementServiceTest() throws Exception { + setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class); doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper(); + doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid(); + + setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); } + private void setupSystemService(Object service, String name, Class serviceClass) { + doReturn(name).when(mMockContext).getSystemServiceName(serviceClass); + doReturn(service).when(mMockContext).getSystemService(name); + } + + private void setupMockedCarrierPrivilege(boolean isPrivileged) { + doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) + .when(mSubMgr) + .getSubscriptionsInGroup(any()); + doReturn(isPrivileged) + .when(mTelMgr) + .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); + } + @Test public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); @@ -59,4 +114,74 @@ public class VcnManagementServiceTest { verify(mConnMgr) .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class)); } + + @Test + public void testSetVcnConfigRequiresNonSystemServer() throws Exception { + doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); + + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + fail("Expected IllegalStateException exception for system server"); + } catch (IllegalStateException expected) { + } + } + + @Test + public void testSetVcnConfigRequiresSystemUser() throws Exception { + doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID)) + .when(mMockDeps) + .getBinderCallingUid(); + + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + fail("Expected security exception for non system user"); + } catch (SecurityException expected) { + } + } + + @Test + public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception { + setupMockedCarrierPrivilege(false); + + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + fail("Expected security exception for missing carrier privileges"); + } catch (SecurityException expected) { + } + } + + @Test + public void testClearVcnConfigRequiresNonSystemServer() throws Exception { + doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); + + try { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + fail("Expected IllegalStateException exception for system server"); + } catch (IllegalStateException expected) { + } + } + + @Test + public void testClearVcnConfigRequiresSystemUser() throws Exception { + doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID)) + .when(mMockDeps) + .getBinderCallingUid(); + + try { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + fail("Expected security exception for non system user"); + } catch (SecurityException expected) { + } + } + + @Test + public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception { + setupMockedCarrierPrivilege(false); + + try { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + fail("Expected security exception for missing carrier privileges"); + } catch (SecurityException expected) { + } + } } From 0b1cdf20e49a1c881931f8cd14f8647e2ee79765 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 10 Aug 2020 17:54:33 -0700 Subject: [PATCH 0016/1057] Implement basic VcnConfig and VcnGatewayConnectionConfig This change adds some of the basic fields in VcnConfig and VcnGatewayConnectionConfig, plus adds a persistability layer to ensure all VcnConfig(s) are disk-stable. Bug: 163602123 Bug: 163594033 Test: New tests added, passing Change-Id: I2e632532809e7768b284be376f2b0a77f634fef5 --- .../src/android/net/vcn/VcnConfig.java | 109 ++++- .../net/vcn/VcnGatewayConnectionConfig.java | 401 +++++++++++++++++- .../src/com/android/server/vcn/Android.bp | 4 + .../java/android/net/vcn/VcnConfigTest.java | 83 ++++ .../vcn/VcnGatewayConnectionConfigTest.java | 143 +++++++ .../server/VcnManagementServiceTest.java | 8 +- 6 files changed, 725 insertions(+), 23 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/Android.bp create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index 148acf1308..d4a3fa7411 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -15,30 +15,104 @@ */ package android.net.vcn; +import static com.android.internal.annotations.VisibleForTesting.Visibility; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; /** * This class represents a configuration for a Virtual Carrier Network. * + *

Each {@link VcnGatewayConnectionConfig} instance added represents a connection that will be + * brought up on demand based on active {@link NetworkRequest}(s). + * + * @see VcnManager for more information on the Virtual Carrier Network feature * @hide */ public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); - private VcnConfig() { + private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; + @NonNull private final Set mGatewayConnectionConfigs; + + private VcnConfig(@NonNull Set tunnelConfigs) { + mGatewayConnectionConfigs = Collections.unmodifiableSet(tunnelConfigs); + validate(); } - // TODO: Implement getters, validators, etc /** - * Validates this configuration. + * Deserializes a VcnConfig from a PersistableBundle. * * @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnConfig(@NonNull PersistableBundle in) { + final PersistableBundle gatewayConnectionConfigsBundle = + in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY); + mGatewayConnectionConfigs = + new ArraySet<>( + PersistableBundleUtils.toList( + gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); + + validate(); + } + private void validate() { - // TODO: implement validation logic + Preconditions.checkCollectionNotEmpty( + mGatewayConnectionConfigs, "gatewayConnectionConfigs"); + } + + /** Retrieves the set of configured tunnels. */ + @NonNull + public Set getGatewayConnectionConfigs() { + return Collections.unmodifiableSet(mGatewayConnectionConfigs); + } + + /** + * Serializes this object to a PersistableBundle. + * + * @hide + */ + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle gatewayConnectionConfigsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mGatewayConnectionConfigs), + VcnGatewayConnectionConfig::toPersistableBundle); + result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash(mGatewayConnectionConfigs); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof VcnConfig)) { + return false; + } + + final VcnConfig rhs = (VcnConfig) other; + return mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); } // Parcelable methods @@ -49,15 +123,16 @@ public final class VcnConfig implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) {} + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(toPersistableBundle(), flags); + } @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @NonNull public VcnConfig createFromParcel(Parcel in) { - // TODO: Ensure all methods are pulled from the parcels - return new VcnConfig(); + return new VcnConfig((PersistableBundle) in.readParcelable(null)); } @NonNull @@ -68,7 +143,23 @@ public final class VcnConfig implements Parcelable { /** This class is used to incrementally build {@link VcnConfig} objects. */ public static class Builder { - // TODO: Implement this builder + @NonNull + private final Set mGatewayConnectionConfigs = new ArraySet<>(); + + /** + * Adds a configuration for an individual gateway connection. + * + * @param gatewayConnectionConfig the configuration for an individual gateway connection + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder addGatewayConnectionConfig( + @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { + Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null"); + + mGatewayConnectionConfigs.add(gatewayConnectionConfig); + return this; + } /** * Builds and validates the VcnConfig. @@ -77,7 +168,7 @@ public final class VcnConfig implements Parcelable { */ @NonNull public VcnConfig build() { - return new VcnConfig(); + return new VcnConfig(mGatewayConnectionConfigs); } } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 8160edc874..039360a69a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,7 +15,27 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NetCapability; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; +import android.os.PersistableBundle; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; /** * This class represents a configuration for a connection to a Virtual Carrier Network gateway. @@ -49,38 +69,399 @@ import android.annotation.NonNull; *

  • {@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX} * * + *

    The meteredness and roaming of the VCN {@link Network} will be determined by that of the + * underlying Network(s). + * * @hide */ public final class VcnGatewayConnectionConfig { - private VcnGatewayConnectionConfig() { + // TODO: Use MIN_MTU_V6 once it is public, @hide + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int MIN_MTU_V6 = 1280; + + private static final Set ALLOWED_CAPABILITIES; + + static { + Set allowedCaps = new ArraySet<>(); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX); + + ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); + } + + private static final int DEFAULT_MAX_MTU = 1500; + + /** + * The maximum number of retry intervals that may be specified. + * + *

    Limited to ensure an upper bound on config sizes. + */ + private static final int MAX_RETRY_INTERVAL_COUNT = 10; + + /** + * The minimum allowable repeating retry interval + * + *

    To ensure the device is not constantly being woken up, this retry interval MUST be greater + * than this value. + * + * @see {@link Builder#setRetryInterval()} + */ + private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); + + private static final long[] DEFAULT_RETRY_INTERVALS_MS = + new long[] { + TimeUnit.SECONDS.toMillis(1), + TimeUnit.SECONDS.toMillis(2), + TimeUnit.SECONDS.toMillis(5), + TimeUnit.SECONDS.toMillis(30), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.MINUTES.toMillis(5), + TimeUnit.MINUTES.toMillis(15) + }; + + private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; + @NonNull private final Set mExposedCapabilities; + + private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; + @NonNull private final Set mUnderlyingCapabilities; + + // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig + + private static final String MAX_MTU_KEY = "mMaxMtu"; + private final int mMaxMtu; + + private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; + @NonNull private final long[] mRetryIntervalsMs; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnGatewayConnectionConfig( + @NonNull Set exposedCapabilities, + @NonNull Set underlyingCapabilities, + @NonNull long[] retryIntervalsMs, + @IntRange(from = MIN_MTU_V6) int maxMtu) { + mExposedCapabilities = exposedCapabilities; + mUnderlyingCapabilities = underlyingCapabilities; + mRetryIntervalsMs = retryIntervalsMs; + mMaxMtu = maxMtu; + validate(); } - // TODO: Implement getters, validators, etc + /** @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { + final PersistableBundle exposedCapsBundle = + in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); + final PersistableBundle underlyingCapsBundle = + in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); + + mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); + mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); + mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); + mMaxMtu = in.getInt(MAX_MTU_KEY); + + validate(); + } + + private void validate() { + Preconditions.checkArgument( + mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), + "exposedCapsBundle was null or empty"); + for (Integer cap : getAllExposedCapabilities()) { + checkValidCapability(cap); + } + + Preconditions.checkArgument( + mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(), + "underlyingCapabilities was null or empty"); + for (Integer cap : getAllUnderlyingCapabilities()) { + checkValidCapability(cap); + } + + Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); + validateRetryInterval(mRetryIntervalsMs); + + Preconditions.checkArgument( + mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + } + + private static void checkValidCapability(int capability) { + Preconditions.checkArgument( + ALLOWED_CAPABILITIES.contains(capability), + "NetworkCapability " + capability + "out of range"); + } + + private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) { + Preconditions.checkArgument( + retryIntervalsMs != null + && retryIntervalsMs.length > 0 + && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT, + "retryIntervalsMs was null, empty or exceed max interval count"); + + final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1]; + if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) { + throw new IllegalArgumentException( + "Repeating retry interval was too short, must be a minimum of 15 minutes: " + + repeatingInterval); + } + } /** - * Validates this configuration + * Returns all exposed capabilities. * * @hide */ - private void validate() { - // TODO: implement validation logic + @NonNull + public Set getAllExposedCapabilities() { + return Collections.unmodifiableSet(mExposedCapabilities); } - // Parcelable methods + /** + * Checks if this config is configured to support/expose a specific capability. + * + * @param capability the capability to check for + */ + public boolean hasExposedCapability(@NetCapability int capability) { + checkValidCapability(capability); - /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects */ + return mExposedCapabilities.contains(capability); + } + + /** + * Returns all capabilities required of underlying networks. + * + * @hide + */ + @NonNull + public Set getAllUnderlyingCapabilities() { + return Collections.unmodifiableSet(mUnderlyingCapabilities); + } + + /** + * Checks if this config requires an underlying network to have the specified capability. + * + * @param capability the capability to check for + */ + public boolean requiresUnderlyingCapability(@NetCapability int capability) { + checkValidCapability(capability); + + return mUnderlyingCapabilities.contains(capability); + } + + /** Retrieves the configured retry intervals. */ + @NonNull + public long[] getRetryIntervalsMs() { + return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); + } + + /** Retrieves the maximum MTU allowed for this Gateway Connection. */ + @IntRange(from = MIN_MTU_V6) + public int getMaxMtu() { + return mMaxMtu; + } + + /** + * Converts this config to a PersistableBundle. + * + * @hide + */ + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle exposedCapsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mExposedCapabilities), + PersistableBundleUtils.INTEGER_SERIALIZER); + final PersistableBundle underlyingCapsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mUnderlyingCapabilities), + PersistableBundleUtils.INTEGER_SERIALIZER); + + result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); + result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); + result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); + result.putInt(MAX_MTU_KEY, mMaxMtu); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash( + mExposedCapabilities, + mUnderlyingCapabilities, + Arrays.hashCode(mRetryIntervalsMs), + mMaxMtu); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof VcnGatewayConnectionConfig)) { + return false; + } + + final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; + return mExposedCapabilities.equals(rhs.mExposedCapabilities) + && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) + && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) + && mMaxMtu == rhs.mMaxMtu; + } + + /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ public static class Builder { - // TODO: Implement this builder + @NonNull private final Set mExposedCapabilities = new ArraySet(); + @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); + @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; + private int mMaxMtu = DEFAULT_MAX_MTU; + + // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent. + // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS + // when on Cell. /** - * Builds and validates the VcnGatewayConnectionConfig + * Add a capability that this VCN Gateway Connection will support. + * + * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway + * Connection (i.e., the capabilities that this VCN Gateway Connection will support). + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway + * Connection + */ + public Builder addExposedCapability(@NetCapability int exposedCapability) { + checkValidCapability(exposedCapability); + + mExposedCapabilities.add(exposedCapability); + return this; + } + + /** + * Remove a capability that this VCN Gateway Connection will support. + * + * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway + * Connection (i.e., the capabilities that this VCN Gateway Connection will support) + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway + * Connection + */ + public Builder removeExposedCapability(@NetCapability int exposedCapability) { + checkValidCapability(exposedCapability); + + mExposedCapabilities.remove(exposedCapability); + return this; + } + + /** + * Require a capability for Networks underlying this VCN Gateway Connection. + * + * @param underlyingCapability the capability that a network MUST have in order to be an + * underlying network for this VCN Gateway Connection. + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying + * networks + */ + public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + checkValidCapability(underlyingCapability); + + mUnderlyingCapabilities.add(underlyingCapability); + return this; + } + + /** + * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection. + * + *

    Calling this method will allow Networks that do NOT have this capability to be + * selected as an underlying network for this VCN Gateway Connection. However, underlying + * networks MAY still have the removed capability. + * + * @param underlyingCapability the capability that a network DOES NOT need to have in order + * to be an underlying network for this VCN Gateway Connection. + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying + * networks + */ + public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + checkValidCapability(underlyingCapability); + + mUnderlyingCapabilities.remove(underlyingCapability); + return this; + } + + /** + * Set the retry interval between VCN establishment attempts upon successive failures. + * + *

    The last retry interval will be repeated until safe mode is entered, or a connection + * is successfully established, at which point the retry timers will be reset. For power + * reasons, the last (repeated) retry interval MUST be at least 15 minutes. + * + *

    Retry intervals MAY be subject to system power saving modes. That is to say that if + * the system enters a power saving mode, the retry may not occur until the device leaves + * the specified power saving mode. Intervals are sequential, and intervals will NOT be + * skipped if system power saving results in delaying retries (even if it exceed multiple + * retry intervals). + * + *

    Each Gateway Connection will retry according to the retry intervals configured, but if + * safe mode is enabled, all Gateway Connection(s) will be disabled. + * + * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which + * the VCN will attempt to retry a session initiation. The last (repeating) retry + * interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m, + * 15m]} + * @return this {@link Builder} instance, for chaining + * @see VcnManager for additional discussion on fail-safe mode + */ + @NonNull + public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { + validateRetryInterval(retryIntervalsMs); + + mRetryIntervalsMs = retryIntervalsMs; + return this; + } + + /** + * Sets the maximum MTU allowed for this VCN Gateway Connection. + * + *

    This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the + * MTU of the virtualized network. + * + *

    The system may reduce the MTU below the maximum specified based on signals such as the + * MTU of the underlying networks (and adjusted for Gateway Connection overhead). + * + * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than + * the IPv6 minimum MTU of 1280. Defaults to 1500. + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { + Preconditions.checkArgument( + maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + + mMaxMtu = maxMtu; + return this; + } + + /** + * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance */ @NonNull public VcnGatewayConnectionConfig build() { - return new VcnGatewayConnectionConfig(); + return new VcnGatewayConnectionConfig( + mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp new file mode 100644 index 0000000000..5ed204fd76 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/Android.bp @@ -0,0 +1,4 @@ +filegroup { + name: "framework-vcn-util-sources", + srcs: ["util/**/*.java"], +} \ No newline at end of file diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java new file mode 100644 index 0000000000..77944deb26 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.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.vcn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnConfigTest { + private static final Set GATEWAY_CONNECTION_CONFIGS = + Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig()); + + // Public visibility for VcnManagementServiceTest + public static VcnConfig buildTestConfig() { + VcnConfig.Builder builder = new VcnConfig.Builder(); + + for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) { + builder.addGatewayConnectionConfig(gatewayConnectionConfig); + } + + return builder.build(); + } + + @Test + public void testBuilderRequiresGatewayConnectionConfig() { + try { + new VcnConfig.Builder().build(); + fail("Expected exception due to no VcnGatewayConnectionConfigs provided"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderAndGetters() { + final VcnConfig config = buildTestConfig(); + + assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs()); + } + + @Test + public void testPersistableBundle() { + final VcnConfig config = buildTestConfig(); + + assertEquals(config, new VcnConfig(config.toPersistableBundle())); + } + + @Test + public void testParceling() { + final VcnConfig config = buildTestConfig(); + + Parcel parcel = Parcel.obtain(); + config.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + assertEquals(config, VcnConfig.CREATOR.createFromParcel(parcel)); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java new file mode 100644 index 0000000000..e98b6ef2b3 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -0,0 +1,143 @@ +/* + * 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.vcn; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.net.NetworkCapabilities; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionConfigTest { + private static final int[] EXPOSED_CAPS = + new int[] { + NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS + }; + private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + private static final long[] RETRY_INTERVALS_MS = + new long[] { + TimeUnit.SECONDS.toMillis(5), + TimeUnit.SECONDS.toMillis(30), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.MINUTES.toMillis(5), + TimeUnit.MINUTES.toMillis(15), + TimeUnit.MINUTES.toMillis(30) + }; + private static final int MAX_MTU = 1360; + + // Package protected for use in VcnConfigTest + static VcnGatewayConnectionConfig buildTestConfig() { + final VcnGatewayConnectionConfig.Builder builder = + new VcnGatewayConnectionConfig.Builder() + .setRetryInterval(RETRY_INTERVALS_MS) + .setMaxMtu(MAX_MTU); + + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + for (int caps : UNDERLYING_CAPS) { + builder.addRequiredUnderlyingCapability(caps); + } + + return builder.build(); + } + + @Test + public void testBuilderRequiresNonEmptyExposedCaps() { + try { + new VcnGatewayConnectionConfig.Builder() + .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + + fail("Expected exception due to invalid exposed capabilities"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonEmptyUnderlyingCaps() { + try { + new VcnGatewayConnectionConfig.Builder() + .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + + fail("Expected exception due to invalid required underlying capabilities"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonNullRetryInterval() { + try { + new VcnGatewayConnectionConfig.Builder().setRetryInterval(null); + fail("Expected exception due to invalid retryIntervalMs"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonEmptyRetryInterval() { + try { + new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]); + fail("Expected exception due to invalid retryIntervalMs"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresValidMtu() { + try { + new VcnGatewayConnectionConfig.Builder() + .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1); + fail("Expected exception due to invalid mtu"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderAndGetters() { + final VcnGatewayConnectionConfig config = buildTestConfig(); + + for (int cap : EXPOSED_CAPS) { + config.hasExposedCapability(cap); + } + for (int cap : UNDERLYING_CAPS) { + config.requiresUnderlyingCapability(cap); + } + + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); + assertEquals(MAX_MTU, config.getMaxMtu()); + } + + @Test + public void testPersistableBundle() { + final VcnGatewayConnectionConfig config = buildTestConfig(); + + assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 633cf64bc2..876e07fbce 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.net.ConnectivityManager; -import android.net.vcn.VcnConfig; +import android.net.vcn.VcnConfigTest; import android.os.ParcelUuid; import android.os.Process; import android.os.UserHandle; @@ -120,7 +120,7 @@ public class VcnManagementServiceTest { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected IllegalStateException exception for system server"); } catch (IllegalStateException expected) { } @@ -133,7 +133,7 @@ public class VcnManagementServiceTest { .getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected security exception for non system user"); } catch (SecurityException expected) { } @@ -144,7 +144,7 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } From 96518dd866ba20f60182d70248fc9d4354abdc24 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 28 Aug 2020 10:09:15 -0700 Subject: [PATCH 0017/1057] Add a TelephonySubscriptionTracker to track subId/subGrp changes This change adds a TelephonySubscriptionTracker that builds a cache of subscription and carrier config events. Bug: 163431879 Test: atest FrameworksVcnTests Change-Id: Ibec2f3ce5071429929fae83ce144105623f1e164 --- .../vcn/TelephonySubscriptionTracker.java | 314 +++++++++++++++++ .../vcn/TelephonySubscriptionTrackerTest.java | 333 ++++++++++++++++++ 2 files changed, 647 insertions(+) create mode 100644 Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java new file mode 100644 index 0000000000..c0608072df --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -0,0 +1,314 @@ +/* + * 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.vcn; + +import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; +import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; +import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; + +/** + * TelephonySubscriptionTracker provides a caching layer for tracking active subscription groups. + * + *

    This class performs two roles: + * + *

      + *
    1. De-noises subscription changes by ensuring that only changes in active and ready + * subscription groups are acted upon + *
    2. Caches mapping between subIds and subscription groups + *
    + * + *

    An subscription group is active and ready if any of its contained subIds has had BOTH the + * {@link CarrierConfigManager#isConfigForIdentifiedCarrier()} return true, AND the subscription is + * listed as active per SubscriptionManager#getAllSubscriptionInfoList(). + * + *

    Note that due to the asynchronous nature of callbacks and broadcasts, the output of this class + * is (only) eventually consistent. + * + * @hide + */ +public class TelephonySubscriptionTracker extends BroadcastReceiver { + @NonNull private static final String TAG = TelephonySubscriptionTracker.class.getSimpleName(); + private static final boolean LOG_DBG = false; // STOPSHIP if true + + @NonNull private final Context mContext; + @NonNull private final Handler mHandler; + @NonNull private final TelephonySubscriptionTrackerCallback mCallback; + @NonNull private final Dependencies mDeps; + + @NonNull private final SubscriptionManager mSubscriptionManager; + @NonNull private final CarrierConfigManager mCarrierConfigManager; + + // TODO (Android T+): Add ability to handle multiple subIds per slot. + @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); + @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; + + @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; + + public TelephonySubscriptionTracker( + @NonNull Context context, + @NonNull Handler handler, + @NonNull TelephonySubscriptionTrackerCallback callback) { + this(context, handler, callback, new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + TelephonySubscriptionTracker( + @NonNull Context context, + @NonNull Handler handler, + @NonNull TelephonySubscriptionTrackerCallback callback, + @NonNull Dependencies deps) { + mContext = Objects.requireNonNull(context, "Missing context"); + mHandler = Objects.requireNonNull(handler, "Missing handler"); + mCallback = Objects.requireNonNull(callback, "Missing callback"); + mDeps = Objects.requireNonNull(deps, "Missing deps"); + + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + + mSubscriptionChangedListener = + new OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + handleSubscriptionsChanged(); + } + }; + } + + /** Registers the receivers, and starts tracking subscriptions. */ + public void register() { + mContext.registerReceiver( + this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); + mSubscriptionManager.addOnSubscriptionsChangedListener( + new HandlerExecutor(mHandler), mSubscriptionChangedListener); + } + + /** Unregisters the receivers, and stops tracking subscriptions. */ + public void unregister() { + mContext.unregisterReceiver(this); + mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); + } + + /** + * Handles subscription changes, correlating available subscriptions and loaded carrier configs + * + *

    The subscription change listener is registered with a HandlerExecutor backed by mHandler, + * so callbacks & broadcasts are all serialized on mHandler, avoiding the need for locking. + */ + public void handleSubscriptionsChanged() { + final Set activeSubGroups = new ArraySet<>(); + final Map newSubIdToGroupMap = new HashMap<>(); + + final List allSubs = mSubscriptionManager.getAllSubscriptionInfoList(); + if (allSubs == null) { + return; // Telephony crashed; no way to verify subscriptions. + } + + // If allSubs is empty, no subscriptions exist. Cache will be cleared by virtue of no active + // subscriptions + for (SubscriptionInfo subInfo : allSubs) { + if (subInfo.getGroupUuid() == null) { + continue; + } + + // Build subId -> subGrp cache + newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid()); + + // Update subscription groups that are both ready, and active. For a group to be + // considered active, both of the following must be true: + // + // 1. A final CARRIER_CONFIG_CHANGED (where config is for an identified carrier) + // broadcast must have been received for the subId + // 2. A active subscription (is loaded into a SIM slot) must be part of the subscription + // group. + if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX + && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) { + activeSubGroups.add(subInfo.getGroupUuid()); + } + } + + final TelephonySubscriptionSnapshot newSnapshot = + new TelephonySubscriptionSnapshot(newSubIdToGroupMap, activeSubGroups); + + // If snapshot was meaningfully updated, fire the callback + if (!newSnapshot.equals(mCurrentSnapshot)) { + mCurrentSnapshot = newSnapshot; + mHandler.post( + () -> { + mCallback.onNewSnapshot(newSnapshot); + }); + } + } + + /** + * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED + * + *

    The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all + * serialized on mHandler, avoiding the need for locking. + */ + @Override + public void onReceive(Context context, Intent intent) { + // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it + // already was for an identified carrier, we can stop waiting for initial load to complete + if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + return; + } + + final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); + final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); + + if (slotId == INVALID_SIM_SLOT_INDEX) { + return; + } + + if (SubscriptionManager.isValidSubscriptionId(subId)) { + final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) { + Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId)); + mReadySubIdsBySlotId.put(slotId, subId); + handleSubscriptionsChanged(); + } + } else { + Slog.v(TAG, "Slot unloaded: " + slotId); + mReadySubIdsBySlotId.remove(slotId); + handleSubscriptionsChanged(); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setReadySubIdsBySlotId(Map readySubIdsBySlotId) { + mReadySubIdsBySlotId.putAll(readySubIdsBySlotId); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + Map getReadySubIdsBySlotId() { + return Collections.unmodifiableMap(mReadySubIdsBySlotId); + } + + /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ + public static class TelephonySubscriptionSnapshot { + private final Map mSubIdToGroupMap; + private final Set mActiveGroups; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + TelephonySubscriptionSnapshot( + @NonNull Map subIdToGroupMap, + @NonNull Set activeGroups) { + mSubIdToGroupMap = Collections.unmodifiableMap( + Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null")); + mActiveGroups = Collections.unmodifiableSet( + Objects.requireNonNull(activeGroups, "activeGroups was null")); + } + + /** Returns the active subscription groups */ + @NonNull + public Set getActiveSubscriptionGroups() { + return mActiveGroups; + } + + /** Returns the Subscription Group for a given subId. */ + @Nullable + public ParcelUuid getGroupForSubId(int subId) { + return mSubIdToGroupMap.get(subId); + } + + /** + * Returns all the subIds in a given group, including available, but inactive subscriptions. + */ + @NonNull + public Set getAllSubIdsInGroup(ParcelUuid subGrp) { + final Set subIds = new ArraySet<>(); + + for (Entry entry : mSubIdToGroupMap.entrySet()) { + if (subGrp.equals(entry.getValue())) { + subIds.add(entry.getKey()); + } + } + + return subIds; + } + + @Override + public int hashCode() { + return Objects.hash(mSubIdToGroupMap, mActiveGroups); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TelephonySubscriptionSnapshot)) { + return false; + } + + final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; + + return mSubIdToGroupMap.equals(other.mSubIdToGroupMap) + && mActiveGroups.equals(other.mActiveGroups); + } + } + + /** + * Interface for listening to changes in subscriptions + * + * @see TelephonySubscriptionTracker + */ + public interface TelephonySubscriptionTrackerCallback { + /** + * Called when subscription information changes, and a new subscription snapshot was taken + * + * @param snapshot the snapshot of subscription information. + */ + void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot); + } + + /** External static dependencies for test injection */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Checks if the given bundle is for an identified carrier */ + public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) { + return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle); + } + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java new file mode 100644 index 0000000000..17b8f64a13 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -0,0 +1,333 @@ +/* + * 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.vcn; + +import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; +import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; +import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; + +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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.ParcelUuid; +import android.os.test.TestLooper; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.util.ArraySet; + +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 java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** Tests for TelephonySubscriptionTracker */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TelephonySubscriptionTrackerTest { + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); + private static final int TEST_SIM_SLOT_INDEX = 1; + private static final int TEST_SUBSCRIPTION_ID_1 = 2; + private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); + private static final int TEST_SUBSCRIPTION_ID_2 = 3; + private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); + private static final Map TEST_SUBID_TO_GROUP_MAP; + + static { + final Map subIdToGroupMap = new HashMap<>(); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID); + TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); + } + + @NonNull private final Context mContext; + @NonNull private final TestLooper mTestLooper; + @NonNull private final Handler mHandler; + @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps; + + @NonNull private final SubscriptionManager mSubscriptionManager; + @NonNull private final CarrierConfigManager mCarrierConfigManager; + + @NonNull private TelephonySubscriptionTrackerCallback mCallback; + @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker; + + public TelephonySubscriptionTrackerTest() { + mContext = mock(Context.class); + mTestLooper = new TestLooper(); + mHandler = new Handler(mTestLooper.getLooper()); + mDeps = mock(TelephonySubscriptionTracker.Dependencies.class); + + mSubscriptionManager = mock(SubscriptionManager.class); + mCarrierConfigManager = mock(CarrierConfigManager.class); + + doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE) + .when(mContext) + .getSystemServiceName(SubscriptionManager.class); + doReturn(mSubscriptionManager) + .when(mContext) + .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + + doReturn(Context.CARRIER_CONFIG_SERVICE) + .when(mContext) + .getSystemServiceName(CarrierConfigManager.class); + doReturn(mCarrierConfigManager) + .when(mContext) + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + + // subId 1, 2 are in same subGrp, only subId 1 is active + doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid(); + doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_2).getGroupUuid(); + doReturn(TEST_SIM_SLOT_INDEX).when(TEST_SUBINFO_1).getSimSlotIndex(); + doReturn(INVALID_SIM_SLOT_INDEX).when(TEST_SUBINFO_2).getSimSlotIndex(); + doReturn(TEST_SUBSCRIPTION_ID_1).when(TEST_SUBINFO_1).getSubscriptionId(); + doReturn(TEST_SUBSCRIPTION_ID_2).when(TEST_SUBINFO_2).getSubscriptionId(); + } + + @Before + public void setUp() throws Exception { + mCallback = mock(TelephonySubscriptionTrackerCallback.class); + mTelephonySubscriptionTracker = + new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); + mTelephonySubscriptionTracker.register(); + + doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any()); + doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2)) + .when(mSubscriptionManager) + .getAllSubscriptionInfoList(); + } + + private IntentFilter getIntentFilter() { + final ArgumentCaptor captor = ArgumentCaptor.forClass(IntentFilter.class); + verify(mContext).registerReceiver(any(), captor.capture(), any(), any()); + + return captor.getValue(); + } + + private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class); + verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture()); + + return captor.getValue(); + } + + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { + Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); + intent.putExtra( + EXTRA_SUBSCRIPTION_INDEX, + hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID); + + return intent; + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot(Set activeSubGroups) { + return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, activeSubGroups); + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + Map subIdToGroupMap, Set activeSubGroups) { + return new TelephonySubscriptionSnapshot(subIdToGroupMap, activeSubGroups); + } + + private void verifyNoActiveSubscriptions() { + verify(mCallback).onNewSnapshot( + argThat(snapshot -> snapshot.getActiveSubscriptionGroups().isEmpty())); + } + + private void setupReadySubIds() { + mTelephonySubscriptionTracker.setReadySubIdsBySlotId( + Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1)); + } + + @Test + public void testRegister() throws Exception { + verify(mContext) + .registerReceiver( + eq(mTelephonySubscriptionTracker), + any(IntentFilter.class), + any(), + eq(mHandler)); + final IntentFilter filter = getIntentFilter(); + assertEquals(1, filter.countActions()); + assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); + + verify(mSubscriptionManager) + .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); + assertNotNull(getOnSubscriptionsChangedListener()); + } + + @Test + public void testUnregister() throws Exception { + mTelephonySubscriptionTracker.unregister(); + + verify(mContext).unregisterReceiver(eq(mTelephonySubscriptionTracker)); + + final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); + verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener)); + } + + @Test + public void testOnSubscriptionsChangedFired_NoReadySubIds() throws Exception { + final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); + listener.onSubscriptionsChanged(); + mTestLooper.dispatchAll(); + + verifyNoActiveSubscriptions(); + } + + @Test + public void testOnSubscriptionsChangedFired_WithReadySubIds() throws Exception { + setupReadySubIds(); + + final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); + listener.onSubscriptionsChanged(); + mTestLooper.dispatchAll(); + + final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + } + + @Test + public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + + final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + } + + @Test + public void testReceiveBroadcast_ConfigReadyNoSubscriptions() throws Exception { + doReturn(new ArrayList()) + .when(mSubscriptionManager) + .getAllSubscriptionInfoList(); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + + // Expect an empty snapshot + verify(mCallback).onNewSnapshot( + eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet()))); + } + + @Test + public void testReceiveBroadcast_SlotCleared() throws Exception { + setupReadySubIds(); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + mTestLooper.dispatchAll(); + + verifyNoActiveSubscriptions(); + assertTrue(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().isEmpty()); + } + + @Test + public void testReceiveBroadcast_ConfigNotReady() throws Exception { + doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any()); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + + // No interactions expected; config was not loaded + verifyNoMoreInteractions(mCallback); + } + + @Test + public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception { + final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + assertNotNull( + mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); + + doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList(); + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + verify(mCallback).onNewSnapshot( + eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet()))); + } + + @Test + public void testSlotClearedAfterValidTriggersCallbacks() throws Exception { + final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + assertNotNull( + mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + mTestLooper.dispatchAll(); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(Collections.emptySet()))); + assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); + } + + @Test + public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { + final TelephonySubscriptionSnapshot snapshot = + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet()); + + assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); + assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); + } + + @Test + public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { + final TelephonySubscriptionSnapshot snapshot = + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet()); + + assertEquals( + new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), + snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID)); + } +} From ef1a02ca39cc076bbdaee6b0874c32c302244931 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 18 Aug 2020 19:49:17 -0700 Subject: [PATCH 0018/1057] Add persistence for VcnConfig objects by Subscription Group This commit adds the ability for the VcnManagementService to track/store VCN profiles by subscription groups, and saving/loading to/from disk. Bug: 163611304 Test: New tests added, passing Change-Id: Ifabf5e2be090d529cd29e2c68d55ece4858b2aad --- .../src/android/net/vcn/VcnManager.java | 16 ++- .../android/server/VcnManagementService.java | 119 +++++++++++++++++- .../server/VcnManagementServiceTest.java | 71 +++++++++++ 3 files changed, 198 insertions(+), 8 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 6769b9e46e..46d1c1c7a2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -23,6 +23,9 @@ import android.annotation.SystemService; import android.content.Context; import android.os.ParcelUuid; import android.os.RemoteException; +import android.os.ServiceSpecificException; + +import java.io.IOException; /** * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. @@ -63,15 +66,20 @@ public final class VcnManager { * @param config the configuration parameters for the VCN * @throws SecurityException if the caller does not have carrier privileges, or is not running * as the primary user + * @throws IOException if the configuration failed to be persisted. A caller encountering this + * exception should attempt to retry (possibly after a delay). * @hide */ @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant - public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) + throws IOException { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(config, "config was null"); try { mService.setVcnConfig(subscriptionGroup, config); + } catch (ServiceSpecificException e) { + throw new IOException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -88,14 +96,18 @@ public final class VcnManager { * @param subscriptionGroup the subscription group that the configuration should be applied to * @throws SecurityException if the caller does not have carrier privileges, or is not running * as the primary user + * @throws IOException if the configuration failed to be cleared. A caller encountering this + * exception should attempt to retry (possibly after a delay). * @hide */ @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant - public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { + public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) throws IOException { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); try { mService.clearVcnConfig(subscriptionGroup); + } catch (ServiceSpecificException e) { + throw new IOException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e9f17fff5a..5e85409b0a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -26,20 +26,31 @@ import android.net.NetworkRequest; import android.net.vcn.IVcnManagementService; import android.net.vcn.VcnConfig; import android.os.Binder; +import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.Process; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.ArrayMap; +import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.util.PersistableBundleUtils; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** * VcnManagementService manages Virtual Carrier Network profiles and lifecycles. @@ -101,20 +112,72 @@ public class VcnManagementService extends IVcnManagementService.Stub { public static final boolean VDBG = false; // STOPSHIP: if true + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; + /* Binder context for this service */ @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; @NonNull private final Looper mLooper; + @NonNull private final Handler mHandler; @NonNull private final VcnNetworkProvider mNetworkProvider; + @GuardedBy("mLock") + @NonNull + private final Map mConfigs = new ArrayMap<>(); + + @NonNull private final Object mLock = new Object(); + + @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper; + @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { mContext = requireNonNull(context, "Missing context"); mDeps = requireNonNull(deps, "Missing dependencies"); mLooper = mDeps.getLooper(); + mHandler = new Handler(mLooper); mNetworkProvider = new VcnNetworkProvider(mContext, mLooper); + + mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); + + // Run on handler to ensure I/O does not block system server startup + mHandler.post(() -> { + PersistableBundle configBundle = null; + try { + configBundle = mConfigDiskRwHelper.readFromDisk(); + } catch (IOException e1) { + Slog.e(TAG, "Failed to read configs from disk; retrying", e1); + + // Retry immediately. The IOException may have been transient. + try { + configBundle = mConfigDiskRwHelper.readFromDisk(); + } catch (IOException e2) { + Slog.wtf(TAG, "Failed to read configs from disk", e2); + return; + } + } + + if (configBundle != null) { + final Map configs = + PersistableBundleUtils.toMap( + configBundle, + PersistableBundleUtils::toParcelUuid, + VcnConfig::new); + + synchronized (mLock) { + for (Entry entry : configs.entrySet()) { + // Ensure no new configs are overwritten; a carrier app may have added a new + // config. + if (!mConfigs.containsKey(entry.getKey())) { + mConfigs.put(entry.getKey(), entry.getValue()); + } + } + // TODO: Trigger re-evaluation of active VCNs; start/stop VCNs as needed. + } + } + }); } // Package-visibility for SystemServer to create instances. @@ -151,12 +214,21 @@ public class VcnManagementService extends IVcnManagementService.Stub { public int getBinderCallingUid() { return Binder.getCallingUid(); } + + /** + * Creates and returns a new {@link PersistableBundle.LockingReadWriteHelper} + * + * @param path the file path to read/write from/to. + * @return the {@link PersistableBundleUtils.LockingReadWriteHelper} instance + */ + public PersistableBundleUtils.LockingReadWriteHelper + newPersistableBundleLockingReadWriteHelper(@NonNull String path) { + return new PersistableBundleUtils.LockingReadWriteHelper(path); + } } /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - // TODO: Retrieve existing profiles from KeyStore - mContext.getSystemService(ConnectivityManager.class) .registerNetworkProvider(mNetworkProvider); } @@ -217,9 +289,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { enforceCallingUserAndCarrierPrivilege(subscriptionGroup); - // TODO: Clear Binder calling identity + synchronized (mLock) { + mConfigs.put(subscriptionGroup, config); - // TODO: Store VCN configuration, trigger startup as necessary + // Must be done synchronously to ensure that writes do not happen out-of-order. + writeConfigsToDiskLocked(); + } + + // TODO: Clear Binder calling identity + // TODO: Trigger startup as necessary } /** @@ -233,9 +311,38 @@ public class VcnManagementService extends IVcnManagementService.Stub { enforceCallingUserAndCarrierPrivilege(subscriptionGroup); - // TODO: Clear Binder calling identity + synchronized (mLock) { + mConfigs.remove(subscriptionGroup); - // TODO: Clear VCN configuration, trigger teardown as necessary + // Must be done synchronously to ensure that writes do not happen out-of-order. + writeConfigsToDiskLocked(); + } + + // TODO: Clear Binder calling identity + // TODO: Trigger teardown as necessary + } + + @GuardedBy("mLock") + private void writeConfigsToDiskLocked() { + try { + PersistableBundle bundle = + PersistableBundleUtils.fromMap( + mConfigs, + PersistableBundleUtils::fromParcelUuid, + VcnConfig::toPersistableBundle); + mConfigDiskRwHelper.writeToDisk(bundle); + } catch (IOException e) { + Slog.e(TAG, "Failed to save configs to disk", e); + throw new ServiceSpecificException(0, "Failed to save configs"); + } + } + + /** Get current configuration list for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + Map getConfigs() { + synchronized (mLock) { + return Collections.unmodifiableMap(mConfigs); + } } /** diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 876e07fbce..1cc953239f 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -16,6 +16,9 @@ package com.android.server; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; @@ -25,8 +28,10 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.net.ConnectivityManager; +import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.Process; import android.os.UserHandle; import android.os.test.TestLooper; @@ -37,10 +42,14 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.util.PersistableBundleUtils; + import org.junit.Test; import org.junit.runner.RunWith; +import java.io.FileNotFoundException; import java.util.Collections; +import java.util.Map; import java.util.UUID; /** Tests for {@link VcnManagementService}. */ @@ -48,6 +57,11 @@ import java.util.UUID; @SmallTest public class VcnManagementServiceTest { private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); + private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); + private static final VcnConfig TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(); + private static final Map TEST_VCN_CONFIG_MAP = + Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG)); + private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO = new SubscriptionInfo( 1 /* id */, @@ -79,6 +93,8 @@ public class VcnManagementServiceTest { private final TelephonyManager mTelMgr = mock(TelephonyManager.class); private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class); private final VcnManagementService mVcnMgmtSvc; + private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper = + mock(PersistableBundleUtils.LockingReadWriteHelper.class); public VcnManagementServiceTest() throws Exception { setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); @@ -88,6 +104,16 @@ public class VcnManagementServiceTest { doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper(); doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid(); + doReturn(mConfigReadWriteHelper) + .when(mMockDeps) + .newPersistableBundleLockingReadWriteHelper(any()); + + final PersistableBundle bundle = + PersistableBundleUtils.fromMap( + TEST_VCN_CONFIG_MAP, + PersistableBundleUtils::fromParcelUuid, + VcnConfig::toPersistableBundle); + doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk(); setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); @@ -115,6 +141,36 @@ public class VcnManagementServiceTest { .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class)); } + @Test + public void testNonSystemServerRealConfigFileAccessPermission() throws Exception { + // Attempt to build a real instance of the dependencies, and verify we cannot write to the + // file. + VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies(); + PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper = + deps.newPersistableBundleLockingReadWriteHelper( + VcnManagementService.VCN_CONFIG_FILE); + + // Even tests should not be able to read/write configs from disk; SELinux policies restrict + // it to only the system server. + // Reading config should always return null since the file "does not exist", and writing + // should throw an IOException. + assertNull(configReadWriteHelper.readFromDisk()); + + try { + configReadWriteHelper.writeToDisk(new PersistableBundle()); + fail("Expected IOException due to SELinux policy"); + } catch (FileNotFoundException expected) { + } + } + + @Test + public void testLoadVcnConfigsOnStartup() throws Exception { + mTestLooper.dispatchAll(); + + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + verify(mConfigReadWriteHelper).readFromDisk(); + } + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -150,6 +206,14 @@ public class VcnManagementServiceTest { } } + @Test + public void testSetVcnConfig() throws Exception { + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG); + assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2)); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + @Test public void testClearVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -184,4 +248,11 @@ public class VcnManagementServiceTest { } catch (SecurityException expected) { } } + + @Test + public void testClearVcnConfig() throws Exception { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } } From b8e3dedbc89a5a3ff540f3ccf8f86727a738f619 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 2 Sep 2020 00:40:23 -0700 Subject: [PATCH 0019/1057] Add additional javadoc for VcnManager This change adds additional detail for the VCN, describing feature set, use cases and fail-safe modes. Bug: 163431877 Test: Compiles, Boots (Comment-only change) Change-Id: I1f82267c20dbbf5875ae27117debdb58f7b96e57 --- .../src/android/net/vcn/VcnManager.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 6769b9e46e..0ee22583f1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -27,6 +27,30 @@ import android.os.RemoteException; /** * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. * + *

    A VCN creates a virtualization layer to allow MVNOs to aggregate heterogeneous physical + * networks, unifying them as a single carrier network. This enables infrastructure flexibility on + * the part of MVNOs without impacting user connectivity, abstracting the physical network + * technologies as an implementation detail of their public network. + * + *

    Each VCN virtualizes an Carrier's network by building tunnels to a carrier's core network over + * carrier-managed physical links and supports a IP mobility layer to ensure seamless transitions + * between the underlying networks. Each VCN is configured based on a Subscription Group (see {@link + * android.telephony.SubscriptionManager}) and aggregates all networks that are brought up based on + * a profile or suggestion in the specified Subscription Group. + * + *

    The VCN can be configured to expose one or more {@link android.net.Network}(s), each with + * different capabilities, allowing for APN virtualization. + * + *

    If a tunnel fails to connect, or otherwise encounters a fatal error, the VCN will attempt to + * reestablish the connection. If the tunnel still has not reconnected after a system-determined + * timeout, the VCN Safe Mode (see below) will be entered. + * + *

    The VCN Safe Mode ensures that users (and carriers) have a fallback to restore system + * connectivity to update profiles, diagnose issues, contact support, or perform other remediation + * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default. + * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will + * automatically exit Safe Mode if all active tunnels connect successfully. + * * @hide */ @SystemService(Context.VCN_MANAGEMENT_SERVICE) From 99cf7b562a78caa305dc1d7c77535e60db4e1d20 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 24 Nov 2020 16:55:06 -0800 Subject: [PATCH 0020/1057] Update VcnManagementService javadoc based on new names of classes This patch updates the VcnManagementService javadoc diagrams. VcnTunnel and VcnInstance were renamed to VcnGatewayConnection and Vcn, respectively. Bug: 163431877 Test: atest FrameworksVcnTests Change-Id: I530d88fb3b145ca4195ba536c16df3894cf929eb --- .../android/server/VcnManagementService.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 165b6a1b08..144f60571d 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -37,12 +37,12 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; * *

    The internal structure of the VCN Management subsystem is as follows:
      *
    - * +------------------------+ 1:1                                 +--------------------------------+
    - * |  VcnManagementService  | ------------ Creates -------------> |  TelephonySubscriptionManager  |
    - * |                        |                                     |                                |
    - * | Manages configs and    |                                     | Tracks subscriptions, carrier  |
    - * | VcnInstance lifecycles | <--- Notifies of subscription & --- | privilege changes, caches maps |
    - * +------------------------+      carrier privilege changes      +--------------------------------+
    + * +-------------------------+ 1:1                                +--------------------------------+
    + * |  VcnManagementService   | ------------ Creates ------------> |  TelephonySubscriptionManager  |
    + * |                         |                                    |                                |
    + * |   Manages configs and   |                                    | Tracks subscriptions, carrier  |
    + * | Vcn instance lifecycles | <--- Notifies of subscription & -- | privilege changes, caches maps |
    + * +-------------------------+      carrier privilege changes     +--------------------------------+
      *      | 1:N          ^
      *      |              |
      *      |              +-------------------------------+
    @@ -54,19 +54,19 @@ import com.android.internal.annotations.VisibleForTesting.Visibility;
      *                      |                      mode state changes
      *                      v                              |
      * +-----------------------------------------------------------------------+
    - * |                              VcnInstance                              |
    + * |                                  Vcn                                  |
      * |                                                                       |
    - * |   Manages tunnel lifecycles based on fulfillable NetworkRequest(s)    |
    - * |                        and overall safe-mode                          |
    + * |       Manages GatewayConnection lifecycles based on fulfillable       |
    + * |                NetworkRequest(s) and overall safe-mode                |
      * +-----------------------------------------------------------------------+
      *                      | 1:N                          ^
      *              Creates to fulfill                     |
    - *           NetworkRequest(s), tears        Notifies of VcnTunnel
    + *           NetworkRequest(s), tears   Notifies of VcnGatewayConnection
      *          down when no longer needed   teardown (e.g. Network reaped)
      *                      |                 and safe-mode timer changes
      *                      v                              |
      * +-----------------------------------------------------------------------+
    - * |                               VcnTunnel                               |
    + * |                          VcnGatewayConnection                         |
      * |                                                                       |
      * |       Manages a single (IKEv2) tunnel session and NetworkAgent,       |
      * |  handles mobility events, (IPsec) Tunnel setup and safe-mode timers   |
    
    From 9e32a9129db890129475ccc4b97954d64383b5cd Mon Sep 17 00:00:00 2001
    From: Benedict Wong 
    Date: Tue, 24 Nov 2020 17:00:23 -0800
    Subject: [PATCH 0021/1057] Add basic VcnMgmtSvc --> Vcn signals (startup,
     teardown, NetworkReq)
    
    This change adds the relevant calls to ensure that the VcnMgmtSvc
    starts, updates and stops a Vcn instance when configs are set/removed
    
    Additionally, this change ensures that upon new network requests, the
    Vcn instance is notified.
    
    Bug: 163432852
    Test: atest FrameworksVcnTests
    Change-Id: Ifec34fad8282a3d64b540d24f643f546463f4379
    ---
     .../android/server/VcnManagementService.java  | 80 +++++++++++++++----
     .../src/com/android/server/vcn/Vcn.java       |  2 +-
     .../server/VcnManagementServiceTest.java      | 42 +++++++++-
     3 files changed, 106 insertions(+), 18 deletions(-)
    
    diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java
    index 74e3851077..6ed4bbb2b3 100644
    --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java
    +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java
    @@ -43,6 +43,8 @@ import android.util.Slog;
     import com.android.internal.annotations.GuardedBy;
     import com.android.internal.annotations.VisibleForTesting;
     import com.android.internal.annotations.VisibleForTesting.Visibility;
    +import com.android.server.vcn.Vcn;
    +import com.android.server.vcn.VcnContext;
     import com.android.server.vcn.util.PersistableBundleUtils;
     
     import java.io.IOException;
    @@ -122,11 +124,16 @@ public class VcnManagementService extends IVcnManagementService.Stub {
         @NonNull private final Looper mLooper;
         @NonNull private final Handler mHandler;
         @NonNull private final VcnNetworkProvider mNetworkProvider;
    +    @NonNull private final VcnContext mVcnContext;
     
         @GuardedBy("mLock")
         @NonNull
         private final Map mConfigs = new ArrayMap<>();
     
    +    @GuardedBy("mLock")
    +    @NonNull
    +    private final Map mVcns = new ArrayMap<>();
    +
         @NonNull private final Object mLock = new Object();
     
         @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
    @@ -141,6 +148,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
             mNetworkProvider = new VcnNetworkProvider(mContext, mLooper);
     
             mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
    +        mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider);
     
             // Run on handler to ensure I/O does not block system server startup
             mHandler.post(() -> {
    @@ -225,6 +233,22 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                     newPersistableBundleLockingReadWriteHelper(@NonNull String path) {
                 return new PersistableBundleUtils.LockingReadWriteHelper(path);
             }
    +
    +        /** Creates a new VcnContext */
    +        public VcnContext newVcnContext(
    +                @NonNull Context context,
    +                @NonNull Looper looper,
    +                @NonNull VcnNetworkProvider vcnNetworkProvider) {
    +            return new VcnContext(context, looper, vcnNetworkProvider);
    +        }
    +
    +        /** Creates a new Vcn instance using the provided configuration */
    +        public Vcn newVcn(
    +                @NonNull VcnContext vcnContext,
    +                @NonNull ParcelUuid subscriptionGroup,
    +                @NonNull VcnConfig config) {
    +            return new Vcn(vcnContext, subscriptionGroup, config);
    +        }
         }
     
         /** Notifies the VcnManagementService that external dependencies can be set up. */
    @@ -277,6 +301,17 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                     "Carrier privilege required for subscription group to set VCN Config");
         }
     
    +    @GuardedBy("mLock")
    +    private void startOrUpdateVcnLocked(
    +            @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
    +        if (mVcns.containsKey(subscriptionGroup)) {
    +            mVcns.get(subscriptionGroup).updateConfig(config);
    +        } else {
    +            final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config);
    +            mVcns.put(subscriptionGroup, newInstance);
    +        }
    +    }
    +
         /**
          * Sets a VCN config for a given subscription group.
          *
    @@ -289,15 +324,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
     
             enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
     
    -        synchronized (mLock) {
    -            mConfigs.put(subscriptionGroup, config);
    +        Binder.withCleanCallingIdentity(() -> {
    +            synchronized (mLock) {
    +                mConfigs.put(subscriptionGroup, config);
    +                startOrUpdateVcnLocked(subscriptionGroup, config);
     
    -            // Must be done synchronously to ensure that writes do not happen out-of-order.
    -            writeConfigsToDiskLocked();
    -        }
    -
    -        // TODO: Clear Binder calling identity
    -        // TODO: Trigger startup as necessary
    +                writeConfigsToDiskLocked();
    +            }
    +        });
         }
     
         /**
    @@ -311,15 +345,17 @@ public class VcnManagementService extends IVcnManagementService.Stub {
     
             enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
     
    -        synchronized (mLock) {
    -            mConfigs.remove(subscriptionGroup);
    +        Binder.withCleanCallingIdentity(() -> {
    +            synchronized (mLock) {
    +                mConfigs.remove(subscriptionGroup);
     
    -            // Must be done synchronously to ensure that writes do not happen out-of-order.
    -            writeConfigsToDiskLocked();
    -        }
    +                if (mVcns.containsKey(subscriptionGroup)) {
    +                    mVcns.remove(subscriptionGroup).teardownAsynchronously();
    +                }
     
    -        // TODO: Clear Binder calling identity
    -        // TODO: Trigger teardown as necessary
    +                writeConfigsToDiskLocked();
    +            }
    +        });
         }
     
         @GuardedBy("mLock")
    @@ -345,6 +381,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
             }
         }
     
    +    /** Get current configuration list for testing purposes */
    +    @VisibleForTesting(visibility = Visibility.PRIVATE)
    +    public Map getAllVcns() {
    +        synchronized (mLock) {
    +            return Collections.unmodifiableMap(mVcns);
    +        }
    +    }
    +
         /**
          * Network provider for VCN networks.
          *
    @@ -357,7 +401,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
     
             @Override
             public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
    -            // TODO: Handle network requests - Ensure VCN started, and start appropriate tunnels.
    +            synchronized (mLock) {
    +                for (Vcn instance : mVcns.values()) {
    +                    instance.onNetworkRequested(request, score, providerId);
    +                }
    +            }
             }
         }
     }
    diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java
    index d51d16b1b4..493761be62 100644
    --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java
    +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java
    @@ -69,7 +69,7 @@ public class Vcn extends Handler {
         }
     
         /** Asynchronously tears down this Vcn instance, along with all tunnels and Networks */
    -    public void teardown() {
    +    public void teardownAsynchronously() {
             // TODO: Proxy to handler, and teardown there.
         }
     
    diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java
    index 1cc953239f..25c614ced0 100644
    --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java
    +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java
    @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNull;
     import static org.junit.Assert.assertTrue;
     import static org.junit.Assert.fail;
     import static org.mockito.Mockito.any;
    +import static org.mockito.Mockito.doAnswer;
     import static org.mockito.Mockito.doReturn;
     import static org.mockito.Mockito.eq;
     import static org.mockito.Mockito.mock;
    @@ -42,6 +43,9 @@ import android.telephony.TelephonyManager;
     import androidx.test.filters.SmallTest;
     import androidx.test.runner.AndroidJUnit4;
     
    +import com.android.server.VcnManagementService.VcnNetworkProvider;
    +import com.android.server.vcn.Vcn;
    +import com.android.server.vcn.VcnContext;
     import com.android.server.vcn.util.PersistableBundleUtils;
     
     import org.junit.Test;
    @@ -92,10 +96,12 @@ public class VcnManagementServiceTest {
         private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
         private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
         private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
    -    private final VcnManagementService mVcnMgmtSvc;
    +    private final VcnContext mVcnContext = mock(VcnContext.class);
         private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
                 mock(PersistableBundleUtils.LockingReadWriteHelper.class);
     
    +    private final VcnManagementService mVcnMgmtSvc;
    +
         public VcnManagementServiceTest() throws Exception {
             setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
             setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
    @@ -104,10 +110,22 @@ public class VcnManagementServiceTest {
     
             doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
             doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid();
    +        doReturn(mVcnContext)
    +                .when(mMockDeps)
    +                .newVcnContext(
    +                        eq(mMockContext),
    +                        eq(mTestLooper.getLooper()),
    +                        any(VcnNetworkProvider.class));
             doReturn(mConfigReadWriteHelper)
                     .when(mMockDeps)
                     .newPersistableBundleLockingReadWriteHelper(any());
     
    +        // Setup VCN instance generation
    +        doAnswer((invocation) -> {
    +            // Mock-within a doAnswer is safe, because it doesn't actually run nested.
    +            return mock(Vcn.class);
    +        }).when(mMockDeps).newVcn(any(), any(), any());
    +
             final PersistableBundle bundle =
                     PersistableBundleUtils.fromMap(
                             TEST_VCN_CONFIG_MAP,
    @@ -255,4 +273,26 @@ public class VcnManagementServiceTest {
             assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
             verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
         }
    +
    +    @Test
    +    public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception {
    +        // Use a different UUID to simulate a new VCN config.
    +        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
    +        final Map vcnInstances = mVcnMgmtSvc.getAllVcns();
    +        final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
    +        assertEquals(1, vcnInstances.size());
    +        assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
    +        verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
    +
    +        // Verify Vcn is started
    +        verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG));
    +
    +        // Verify Vcn is updated if it was previously started
    +        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
    +        verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
    +
    +        // Verify Vcn is stopped if it was already started
    +        mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
    +        verify(vcnInstance).teardownAsynchronously();
    +    }
     }
    
    From 391551a8a9485e48cd0dea91713fe8fd3e2ab5b4 Mon Sep 17 00:00:00 2001
    From: Benedict Wong 
    Date: Fri, 28 Aug 2020 15:46:20 -0700
    Subject: [PATCH 0022/1057] Add TelephonySubscriptionTracker to VcnMgmtSvc
    
    This changes adds the TelephonySubscriptionTracker to
    VcnManagementService, ensuring that VCN Instances are only ever started
    once a relevant Subscription has been loaded in Telephony
    
    Bug: 163430955
    Test: New VcnManagementService tests added, passing
    Change-Id: Ia9396d66b41fadc0a5ed7aa66306e6223a2d29b8
    ---
     .../android/server/VcnManagementService.java  |  98 +++++++++++++++-
     .../vcn/TelephonySubscriptionTracker.java     |   3 +
     .../server/VcnManagementServiceTest.java      | 110 +++++++++++++++++-
     3 files changed, 207 insertions(+), 4 deletions(-)
    
    diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java
    index 6ed4bbb2b3..56bd1a82b3 100644
    --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java
    +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java
    @@ -16,6 +16,9 @@
     
     package com.android.server;
     
    +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
    +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
    +
     import static java.util.Objects.requireNonNull;
     
     import android.annotation.NonNull;
    @@ -43,6 +46,7 @@ import android.util.Slog;
     import com.android.internal.annotations.GuardedBy;
     import com.android.internal.annotations.VisibleForTesting;
     import com.android.internal.annotations.VisibleForTesting.Visibility;
    +import com.android.server.vcn.TelephonySubscriptionTracker;
     import com.android.server.vcn.Vcn;
     import com.android.server.vcn.VcnContext;
     import com.android.server.vcn.util.PersistableBundleUtils;
    @@ -53,6 +57,7 @@ import java.util.Collections;
     import java.util.List;
     import java.util.Map;
     import java.util.Map.Entry;
    +import java.util.concurrent.TimeUnit;
     
     /**
      * VcnManagementService manages Virtual Carrier Network profiles and lifecycles.
    @@ -117,6 +122,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml";
     
    +    @VisibleForTesting(visibility = Visibility.PRIVATE)
    +    static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
    +
         /* Binder context for this service */
         @NonNull private final Context mContext;
         @NonNull private final Dependencies mDeps;
    @@ -124,6 +132,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
         @NonNull private final Looper mLooper;
         @NonNull private final Handler mHandler;
         @NonNull private final VcnNetworkProvider mNetworkProvider;
    +    @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb;
    +    @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
         @NonNull private final VcnContext mVcnContext;
     
         @GuardedBy("mLock")
    @@ -134,6 +144,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
         @NonNull
         private final Map mVcns = new ArrayMap<>();
     
    +    @GuardedBy("mLock")
    +    @NonNull
    +    private TelephonySubscriptionSnapshot mLastSnapshot =
    +            TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT;
    +
         @NonNull private final Object mLock = new Object();
     
         @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
    @@ -146,6 +161,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
             mLooper = mDeps.getLooper();
             mHandler = new Handler(mLooper);
             mNetworkProvider = new VcnNetworkProvider(mContext, mLooper);
    +        mTelephonySubscriptionTrackerCb = new VcnSubscriptionTrackerCallback();
    +        mTelephonySubscriptionTracker = mDeps.newTelephonySubscriptionTracker(
    +                mContext, mLooper, mTelephonySubscriptionTrackerCb);
     
             mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
             mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider);
    @@ -182,7 +200,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                                 mConfigs.put(entry.getKey(), entry.getValue());
                             }
                         }
    -                    // TODO: Trigger re-evaluation of active VCNs; start/stop VCNs as needed.
    +
    +                    // Re-evaluate subscriptions, and start/stop VCNs. This starts with an empty
    +                    // snapshot, and therefore safe even before telephony subscriptions are loaded.
    +                    mTelephonySubscriptionTrackerCb.onNewSnapshot(mLastSnapshot);
                     }
                 }
             });
    @@ -211,6 +232,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                 return mHandlerThread.getLooper();
             }
     
    +        /** Creates a new VcnInstance using the provided configuration */
    +        public TelephonySubscriptionTracker newTelephonySubscriptionTracker(
    +                @NonNull Context context,
    +                @NonNull Looper looper,
    +                @NonNull TelephonySubscriptionTrackerCallback callback) {
    +            return new TelephonySubscriptionTracker(context, new Handler(looper), callback);
    +        }
    +
             /**
              * Retrieves the caller's UID
              *
    @@ -255,6 +284,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
         public void systemReady() {
             mContext.getSystemService(ConnectivityManager.class)
                     .registerNetworkProvider(mNetworkProvider);
    +        mTelephonySubscriptionTracker.register();
         }
     
         private void enforcePrimaryUser() {
    @@ -301,14 +331,74 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                     "Carrier privilege required for subscription group to set VCN Config");
         }
     
    +    private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback {
    +        /**
    +         * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker}
    +         *
    +         * 

    Start any unstarted VCN instances + * + * @hide + */ + public void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + // Startup VCN instances + synchronized (mLock) { + mLastSnapshot = snapshot; + + // Start any VCN instances as necessary + for (Entry entry : mConfigs.entrySet()) { + if (snapshot.getActiveSubscriptionGroups().contains(entry.getKey())) { + // TODO: Add checks to ensure provisioning app is currently carrier + // privileged on this subscription + if (!mVcns.containsKey(entry.getKey())) { + startVcnLocked(entry.getKey(), entry.getValue()); + } + + // Cancel any scheduled teardowns for active subscriptions + mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey())); + } + } + + // Schedule teardown of any VCN instances that have lost carrier privileges (after a + // delay) + for (Entry entry : mVcns.entrySet()) { + if (!snapshot.getActiveSubscriptionGroups().contains(entry.getKey())) { + final ParcelUuid uuidToTeardown = entry.getKey(); + final Vcn instanceToTeardown = entry.getValue(); + + mHandler.postDelayed(() -> { + synchronized (mLock) { + // Guard against case where this is run after a old instance was + // torn down, and a new instance was started. Verify to ensure + // correct instance is torn down. This could happen as a result of a + // Carrier App manually removing/adding a VcnConfig. + if (mVcns.get(uuidToTeardown) == instanceToTeardown) { + mVcns.remove(uuidToTeardown).teardownAsynchronously(); + } + } + }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + } + } + } + } + } + + @GuardedBy("mLock") + private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + + final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config); + mVcns.put(subscriptionGroup, newInstance); + } + @GuardedBy("mLock") private void startOrUpdateVcnLocked( @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); + if (mVcns.containsKey(subscriptionGroup)) { mVcns.get(subscriptionGroup).updateConfig(config); } else { - final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config); - mVcns.put(subscriptionGroup, newInstance); + startVcnLocked(subscriptionGroup, config); } } @@ -321,6 +411,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(config, "config was null"); + Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup); enforceCallingUserAndCarrierPrivilege(subscriptionGroup); @@ -342,6 +433,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @Override public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); enforceCallingUserAndCarrierPrivilege(subscriptionGroup); diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index c0608072df..9c9ca3df47 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -233,6 +233,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { private final Map mSubIdToGroupMap; private final Set mActiveGroups; + public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = + new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptySet()); + @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( @NonNull Map subIdToGroupMap, diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 25c614ced0..04091bc055 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -16,6 +16,9 @@ package com.android.server; +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -25,6 +28,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.Context; @@ -44,16 +48,19 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.VcnManagementService.VcnNetworkProvider; +import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.util.PersistableBundleUtils; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.io.FileNotFoundException; import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.UUID; /** Tests for {@link VcnManagementService}. */ @@ -66,9 +73,10 @@ public class VcnManagementServiceTest { private static final Map TEST_VCN_CONFIG_MAP = Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG)); + private static final int TEST_SUBSCRIPTION_ID = 1; private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO = new SubscriptionInfo( - 1 /* id */, + TEST_SUBSCRIPTION_ID /* id */, "" /* iccId */, 0 /* simSlotIndex */, "Carrier" /* displayName */, @@ -99,6 +107,8 @@ public class VcnManagementServiceTest { private final VcnContext mVcnContext = mock(VcnContext.class); private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper = mock(PersistableBundleUtils.LockingReadWriteHelper.class); + private final TelephonySubscriptionTracker mSubscriptionTracker = + mock(TelephonySubscriptionTracker.class); private final VcnManagementService mVcnMgmtSvc; @@ -116,6 +126,12 @@ public class VcnManagementServiceTest { eq(mMockContext), eq(mTestLooper.getLooper()), any(VcnNetworkProvider.class)); + doReturn(mSubscriptionTracker) + .when(mMockDeps) + .newTelephonySubscriptionTracker( + eq(mMockContext), + eq(mTestLooper.getLooper()), + any(TelephonySubscriptionTrackerCallback.class)); doReturn(mConfigReadWriteHelper) .when(mMockDeps) .newPersistableBundleLockingReadWriteHelper(any()); @@ -135,6 +151,9 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + + // Make sure the profiles are loaded. + mTestLooper.dispatchAll(); } private void setupSystemService(Object service, String name, Class serviceClass) { @@ -157,6 +176,7 @@ public class VcnManagementServiceTest { verify(mConnMgr) .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class)); + verify(mSubscriptionTracker).register(); } @Test @@ -189,6 +209,94 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).readFromDisk(); } + private void triggerSubscriptionTrackerCallback(Set activeSubscriptionGroups) { + final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); + doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + cb.onNewSnapshot(snapshot); + } + + private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class); + verify(mMockDeps) + .newTelephonySubscriptionTracker( + eq(mMockContext), eq(mTestLooper.getLooper()), captor.capture()); + return captor.getValue(); + } + + private Vcn startAndGetVcnInstance(ParcelUuid uuid) { + mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG); + return mVcnMgmtSvc.getAllVcns().get(uuid); + } + + @Test + public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { + triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_1)); + verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG)); + } + + @Test + public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception { + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + triggerSubscriptionTrackerCallback(Collections.emptySet()); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() + throws Exception { + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCallback(Collections.emptySet()); + + // Simulate new SIM loaded right during teardown delay. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); + mTestLooper.dispatchAll(); + triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_2)); + + // Verify that even after the full timeout duration, the VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn, never()).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCallback(Collections.emptySet()); + + // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new + // vcnInstance. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS - 1); + mTestLooper.dispatchAll(); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Verify that new instance was different, and the old one was torn down + assertTrue(oldInstance != newInstance); + verify(oldInstance).teardownAsynchronously(); + + // Verify that even after the full timeout duration, the new VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(newInstance, never()).teardownAsynchronously(); + } + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); From d876d15779620522b4ea265e4793100460331c38 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 30 Nov 2020 17:25:46 -0800 Subject: [PATCH 0023/1057] Verify carrier privileges for VCN-providing packages This change adds and verifies packages in the VcnManagmentService, ensuring that carrier privilege gain/loss correctly starts/tears down VCN instances. Bug: 163431877 Test: atest FrameworksNetTests Change-Id: I63203188c57fdde1cfc58aaf1108aa3e70eb4a50 --- .../net/vcn/IVcnManagementService.aidl | 2 +- .../src/android/net/vcn/VcnConfig.java | 43 ++++++-- .../src/android/net/vcn/VcnManager.java | 2 +- .../android/server/VcnManagementService.java | 23 +++- .../vcn/TelephonySubscriptionTracker.java | 63 ++++++++--- .../java/android/net/vcn/VcnConfigTest.java | 35 ++++-- .../server/VcnManagementServiceTest.java | 58 ++++++++-- .../vcn/TelephonySubscriptionTrackerTest.java | 100 ++++++++++++++---- 8 files changed, 261 insertions(+), 65 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 9dd01140b4..04b585cdf4 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -23,6 +23,6 @@ import android.os.ParcelUuid; * @hide */ interface IVcnManagementService { - void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config); + void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); void clearVcnConfig(in ParcelUuid subscriptionGroup); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index d4a3fa7411..ede8faaaf2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -19,6 +19,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -45,11 +46,17 @@ import java.util.Set; public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); + private static final String PACKAGE_NAME_KEY = "mPackageName"; + @NonNull private final String mPackageName; + private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; @NonNull private final Set mGatewayConnectionConfigs; - private VcnConfig(@NonNull Set tunnelConfigs) { - mGatewayConnectionConfigs = Collections.unmodifiableSet(tunnelConfigs); + private VcnConfig( + @NonNull String packageName, + @NonNull Set gatewayConnectionConfigs) { + mPackageName = packageName; + mGatewayConnectionConfigs = Collections.unmodifiableSet(gatewayConnectionConfigs); validate(); } @@ -61,6 +68,8 @@ public final class VcnConfig implements Parcelable { */ @VisibleForTesting(visibility = Visibility.PRIVATE) public VcnConfig(@NonNull PersistableBundle in) { + mPackageName = in.getString(PACKAGE_NAME_KEY); + final PersistableBundle gatewayConnectionConfigsBundle = in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY); mGatewayConnectionConfigs = @@ -72,8 +81,19 @@ public final class VcnConfig implements Parcelable { } private void validate() { + Objects.requireNonNull(mPackageName, "packageName was null"); Preconditions.checkCollectionNotEmpty( - mGatewayConnectionConfigs, "gatewayConnectionConfigs"); + mGatewayConnectionConfigs, "gatewayConnectionConfigs was empty"); + } + + /** + * Retrieve the package name of the provisioning app. + * + * @hide + */ + @NonNull + public String getProvisioningPackageName() { + return mPackageName; } /** Retrieves the set of configured tunnels. */ @@ -91,6 +111,8 @@ public final class VcnConfig implements Parcelable { public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); + result.putString(PACKAGE_NAME_KEY, mPackageName); + final PersistableBundle gatewayConnectionConfigsBundle = PersistableBundleUtils.fromList( new ArrayList<>(mGatewayConnectionConfigs), @@ -102,7 +124,7 @@ public final class VcnConfig implements Parcelable { @Override public int hashCode() { - return Objects.hash(mGatewayConnectionConfigs); + return Objects.hash(mPackageName, mGatewayConnectionConfigs); } @Override @@ -112,7 +134,8 @@ public final class VcnConfig implements Parcelable { } final VcnConfig rhs = (VcnConfig) other; - return mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); + return mPackageName.equals(rhs.mPackageName) + && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); } // Parcelable methods @@ -143,9 +166,17 @@ public final class VcnConfig implements Parcelable { /** This class is used to incrementally build {@link VcnConfig} objects. */ public static class Builder { + @NonNull private final String mPackageName; + @NonNull private final Set mGatewayConnectionConfigs = new ArraySet<>(); + public Builder(@NonNull Context context) { + Objects.requireNonNull(context, "context was null"); + + mPackageName = context.getOpPackageName(); + } + /** * Adds a configuration for an individual gateway connection. * @@ -168,7 +199,7 @@ public final class VcnConfig implements Parcelable { */ @NonNull public VcnConfig build() { - return new VcnConfig(mGatewayConnectionConfigs); + return new VcnConfig(mPackageName, mGatewayConnectionConfigs); } } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 19c183f9fe..b881a33953 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -101,7 +101,7 @@ public final class VcnManager { requireNonNull(config, "config was null"); try { - mService.setVcnConfig(subscriptionGroup, config); + mService.setVcnConfig(subscriptionGroup, config, mContext.getOpPackageName()); } catch (ServiceSpecificException e) { throw new IOException(e); } catch (RemoteException e) { diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 56bd1a82b3..77e8e96a51 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -22,6 +22,7 @@ import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubsc import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkProvider; @@ -122,6 +123,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; + // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS @VisibleForTesting(visibility = Visibility.PRIVATE) static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30); @@ -346,9 +348,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { - if (snapshot.getActiveSubscriptionGroups().contains(entry.getKey())) { - // TODO: Add checks to ensure provisioning app is currently carrier - // privileged on this subscription + if (snapshot.packageHasPermissionsForSubscriptionGroup( + entry.getKey(), entry.getValue().getProvisioningPackageName())) { if (!mVcns.containsKey(entry.getKey())) { startVcnLocked(entry.getKey(), entry.getValue()); } @@ -361,7 +362,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Schedule teardown of any VCN instances that have lost carrier privileges (after a // delay) for (Entry entry : mVcns.entrySet()) { - if (!snapshot.getActiveSubscriptionGroups().contains(entry.getKey())) { + final VcnConfig config = mConfigs.get(entry.getKey()); + if (config == null + || !snapshot.packageHasPermissionsForSubscriptionGroup( + entry.getKey(), config.getProvisioningPackageName())) { final ParcelUuid uuidToTeardown = entry.getKey(); final Vcn instanceToTeardown = entry.getValue(); @@ -408,11 +412,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { *

    Implements the IVcnManagementService Binder interface. */ @Override - public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { + public void setVcnConfig( + @NonNull ParcelUuid subscriptionGroup, + @NonNull VcnConfig config, + @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(config, "config was null"); + requireNonNull(opPkgName, "opPkgName was null"); + if (!config.getProvisioningPackageName().equals(opPkgName)) { + throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); + } Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup); + mContext.getSystemService(AppOpsManager.class) + .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); enforceCallingUserAndCarrierPrivilege(subscriptionGroup); Binder.withCleanCallingIdentity(() -> { diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 9c9ca3df47..d8a145d9ae 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -36,6 +36,8 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -79,6 +81,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final TelephonySubscriptionTrackerCallback mCallback; @NonNull private final Dependencies mDeps; + @NonNull private final TelephonyManager mTelephonyManager; @NonNull private final SubscriptionManager mSubscriptionManager; @NonNull private final CarrierConfigManager mCarrierConfigManager; @@ -106,6 +109,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mCallback = Objects.requireNonNull(callback, "Missing callback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); @@ -139,7 +143,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { * so callbacks & broadcasts are all serialized on mHandler, avoiding the need for locking. */ public void handleSubscriptionsChanged() { - final Set activeSubGroups = new ArraySet<>(); + final Map> privilegedPackages = new HashMap<>(); final Map newSubIdToGroupMap = new HashMap<>(); final List allSubs = mSubscriptionManager.getAllSubscriptionInfoList(); @@ -166,12 +170,22 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { // group. if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) { - activeSubGroups.add(subInfo.getGroupUuid()); + // TODO (b/172619301): Cache based on callbacks from CarrierPrivilegesTracker + + final TelephonyManager subIdSpecificTelephonyManager = + mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); + + final ParcelUuid subGroup = subInfo.getGroupUuid(); + final Set pkgs = + privilegedPackages.getOrDefault(subGroup, new ArraySet<>()); + pkgs.addAll(subIdSpecificTelephonyManager.getPackagesWithCarrierPrivileges()); + + privilegedPackages.put(subGroup, pkgs); } } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToGroupMap, activeSubGroups); + new TelephonySubscriptionSnapshot(newSubIdToGroupMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -231,25 +245,40 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { private final Map mSubIdToGroupMap; - private final Set mActiveGroups; + private final Map> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = - new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptySet()); + new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap()); @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( @NonNull Map subIdToGroupMap, - @NonNull Set activeGroups) { - mSubIdToGroupMap = Collections.unmodifiableMap( - Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null")); - mActiveGroups = Collections.unmodifiableSet( - Objects.requireNonNull(activeGroups, "activeGroups was null")); + @NonNull Map> privilegedPackages) { + Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"); + Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); + + mSubIdToGroupMap = Collections.unmodifiableMap(subIdToGroupMap); + + final Map> unmodifiableInnerSets = new ArrayMap<>(); + for (Entry> entry : privilegedPackages.entrySet()) { + unmodifiableInnerSets.put( + entry.getKey(), Collections.unmodifiableSet(entry.getValue())); + } + mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets); } /** Returns the active subscription groups */ @NonNull public Set getActiveSubscriptionGroups() { - return mActiveGroups; + return mPrivilegedPackages.keySet(); + } + + /** Checks if the provided package is carrier privileged for the specified sub group. */ + public boolean packageHasPermissionsForSubscriptionGroup( + @NonNull ParcelUuid subGrp, @NonNull String packageName) { + final Set privilegedPackages = mPrivilegedPackages.get(subGrp); + + return privilegedPackages != null && privilegedPackages.contains(packageName); } /** Returns the Subscription Group for a given subId. */ @@ -276,7 +305,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public int hashCode() { - return Objects.hash(mSubIdToGroupMap, mActiveGroups); + return Objects.hash(mSubIdToGroupMap, mPrivilegedPackages); } @Override @@ -288,7 +317,15 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; return mSubIdToGroupMap.equals(other.mSubIdToGroupMap) - && mActiveGroups.equals(other.mActiveGroups); + && mPrivilegedPackages.equals(other.mPrivilegedPackages); + } + + @Override + public String toString() { + return "TelephonySubscriptionSnapshot{ " + + "mSubIdToGroupMap=" + mSubIdToGroupMap + + ", mPrivilegedPackages=" + mPrivilegedPackages + + " }"; } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java index 77944deb26..c1ef350e5c 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java @@ -18,12 +18,17 @@ package android.net.vcn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import android.annotation.NonNull; +import android.content.Context; import android.os.Parcel; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,12 +38,15 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnConfigTest { + private static final String TEST_PACKAGE_NAME = VcnConfigTest.class.getPackage().getName(); private static final Set GATEWAY_CONNECTION_CONFIGS = Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig()); + private final Context mContext = mock(Context.class); + // Public visibility for VcnManagementServiceTest - public static VcnConfig buildTestConfig() { - VcnConfig.Builder builder = new VcnConfig.Builder(); + public static VcnConfig buildTestConfig(@NonNull Context context) { + VcnConfig.Builder builder = new VcnConfig.Builder(context); for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) { builder.addGatewayConnectionConfig(gatewayConnectionConfig); @@ -47,10 +55,24 @@ public class VcnConfigTest { return builder.build(); } + @Before + public void setUp() throws Exception { + doReturn(TEST_PACKAGE_NAME).when(mContext).getOpPackageName(); + } + + @Test + public void testBuilderConstructorRequiresContext() { + try { + new VcnConfig.Builder(null); + fail("Expected exception due to null context"); + } catch (NullPointerException e) { + } + } + @Test public void testBuilderRequiresGatewayConnectionConfig() { try { - new VcnConfig.Builder().build(); + new VcnConfig.Builder(mContext).build(); fail("Expected exception due to no VcnGatewayConnectionConfigs provided"); } catch (IllegalArgumentException e) { } @@ -58,21 +80,22 @@ public class VcnConfigTest { @Test public void testBuilderAndGetters() { - final VcnConfig config = buildTestConfig(); + final VcnConfig config = buildTestConfig(mContext); + assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName()); assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs()); } @Test public void testPersistableBundle() { - final VcnConfig config = buildTestConfig(); + final VcnConfig config = buildTestConfig(mContext); assertEquals(config, new VcnConfig(config.toPersistableBundle())); } @Test public void testParceling() { - final VcnConfig config = buildTestConfig(); + final VcnConfig config = buildTestConfig(mContext); Parcel parcel = Parcel.obtain(); config.writeToParcel(parcel, 0); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 04091bc055..d2caa8f0be 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -31,6 +32,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.vcn.VcnConfig; @@ -67,9 +69,20 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + private static final String TEST_PACKAGE_NAME = + VcnManagementServiceTest.class.getPackage().getName(); private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); - private static final VcnConfig TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(); + private static final VcnConfig TEST_VCN_CONFIG; + private static final int TEST_UID = Process.FIRST_APPLICATION_UID; + + static { + final Context mockConfigContext = mock(Context.class); + doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); + + TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext); + } + private static final Map TEST_VCN_CONFIG_MAP = Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG)); @@ -104,6 +117,7 @@ public class VcnManagementServiceTest { private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class); private final TelephonyManager mTelMgr = mock(TelephonyManager.class); private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class); + private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class); private final VcnContext mVcnContext = mock(VcnContext.class); private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper = mock(PersistableBundleUtils.LockingReadWriteHelper.class); @@ -117,9 +131,12 @@ public class VcnManagementServiceTest { setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); setupSystemService( mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class); + setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); + + doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName(); doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper(); - doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid(); + doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid(); doReturn(mVcnContext) .when(mMockDeps) .newVcnContext( @@ -213,6 +230,16 @@ public class VcnManagementServiceTest { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); + final Set privilegedPackages = + (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) + ? Collections.emptySet() + : Collections.singleton(TEST_PACKAGE_NAME); + doReturn(true) + .when(snapshot) + .packageHasPermissionsForSubscriptionGroup( + argThat(val -> activeSubscriptionGroups.contains(val)), + eq(TEST_PACKAGE_NAME)); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); cb.onNewSnapshot(snapshot); } @@ -227,7 +254,7 @@ public class VcnManagementServiceTest { } private Vcn startAndGetVcnInstance(ParcelUuid uuid) { - mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG); + mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); return mVcnMgmtSvc.getAllVcns().get(uuid); } @@ -302,7 +329,7 @@ public class VcnManagementServiceTest { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); fail("Expected IllegalStateException exception for system server"); } catch (IllegalStateException expected) { } @@ -310,12 +337,12 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigRequiresSystemUser() throws Exception { - doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID)) + doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) .when(mMockDeps) .getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); fail("Expected security exception for non system user"); } catch (SecurityException expected) { } @@ -326,16 +353,25 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } } + @Test + public void testSetVcnConfigMismatchedPackages() throws Exception { + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage"); + fail("Expected exception due to mismatched packages in config and method call"); + } catch (IllegalArgumentException expected) { + } + } + @Test public void testSetVcnConfig() throws Exception { // Use a different UUID to simulate a new VCN config. - mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2)); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } @@ -353,7 +389,7 @@ public class VcnManagementServiceTest { @Test public void testClearVcnConfigRequiresSystemUser() throws Exception { - doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID)) + doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) .when(mMockDeps) .getBinderCallingUid(); @@ -385,7 +421,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { // Use a different UUID to simulate a new VCN config. - mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2); assertEquals(1, vcnInstances.size()); @@ -396,7 +432,7 @@ public class VcnManagementServiceTest { verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG)); // Verify Vcn is updated if it was previously started - mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); verify(vcnInstance).updateConfig(TEST_VCN_CONFIG); // Verify Vcn is stopped if it was already started diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 17b8f64a13..528f240b99 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -37,6 +38,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static java.util.Collections.singletonMap; + import android.annotation.NonNull; import android.content.Context; import android.content.Intent; @@ -49,6 +54,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyManager; import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -63,6 +69,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -71,12 +78,16 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class TelephonySubscriptionTrackerTest { + private static final String PACKAGE_NAME = + TelephonySubscriptionTrackerTest.class.getPackage().getName(); private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); + private static final Map> TEST_PRIVILEGED_PACKAGES = + Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME)); private static final Map TEST_SUBID_TO_GROUP_MAP; static { @@ -91,6 +102,7 @@ public class TelephonySubscriptionTrackerTest { @NonNull private final Handler mHandler; @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps; + @NonNull private final TelephonyManager mTelephonyManager; @NonNull private final SubscriptionManager mSubscriptionManager; @NonNull private final CarrierConfigManager mCarrierConfigManager; @@ -103,9 +115,15 @@ public class TelephonySubscriptionTrackerTest { mHandler = new Handler(mTestLooper.getLooper()); mDeps = mock(TelephonySubscriptionTracker.Dependencies.class); + mTelephonyManager = mock(TelephonyManager.class); mSubscriptionManager = mock(SubscriptionManager.class); mCarrierConfigManager = mock(CarrierConfigManager.class); + doReturn(Context.TELEPHONY_SERVICE) + .when(mContext) + .getSystemServiceName(TelephonyManager.class); + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE) .when(mContext) .getSystemServiceName(SubscriptionManager.class); @@ -140,6 +158,9 @@ public class TelephonySubscriptionTrackerTest { doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2)) .when(mSubscriptionManager) .getAllSubscriptionInfoList(); + + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt()); + setPrivilegedPackagesForMock(Collections.singletonList(PACKAGE_NAME)); } private IntentFilter getIntentFilter() { @@ -167,13 +188,15 @@ public class TelephonySubscriptionTrackerTest { return intent; } - private TelephonySubscriptionSnapshot buildExpectedSnapshot(Set activeSubGroups) { - return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, activeSubGroups); + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + Map> privilegedPackages) { + return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, privilegedPackages); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( - Map subIdToGroupMap, Set activeSubGroups) { - return new TelephonySubscriptionSnapshot(subIdToGroupMap, activeSubGroups); + Map subIdToGroupMap, + Map> privilegedPackages) { + return new TelephonySubscriptionSnapshot(subIdToGroupMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -186,6 +209,10 @@ public class TelephonySubscriptionTrackerTest { Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1)); } + private void setPrivilegedPackagesForMock(@NonNull List privilegedPackages) { + doReturn(privilegedPackages).when(mTelephonyManager).getPackagesWithCarrierPrivileges(); + } + @Test public void testRegister() throws Exception { verify(mContext) @@ -223,15 +250,30 @@ public class TelephonySubscriptionTrackerTest { } @Test - public void testOnSubscriptionsChangedFired_WithReadySubIds() throws Exception { + public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages() + throws Exception { + setupReadySubIds(); + setPrivilegedPackagesForMock(Collections.emptyList()); + + final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); + listener.onSubscriptionsChanged(); + mTestLooper.dispatchAll(); + + final Map> privilegedPackages = + Collections.singletonMap(TEST_PARCEL_UUID, new ArraySet<>()); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(privilegedPackages))); + } + + @Test + public void testOnSubscriptionsChangedFired_WithReadySubidsAndPrivilegedPackages() + throws Exception { setupReadySubIds(); final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); listener.onSubscriptionsChanged(); mTestLooper.dispatchAll(); - final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } @Test @@ -239,8 +281,7 @@ public class TelephonySubscriptionTrackerTest { mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); mTestLooper.dispatchAll(); - final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } @Test @@ -253,8 +294,7 @@ public class TelephonySubscriptionTrackerTest { mTestLooper.dispatchAll(); // Expect an empty snapshot - verify(mCallback).onNewSnapshot( - eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet()))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap()))); } @Test @@ -281,41 +321,57 @@ public class TelephonySubscriptionTrackerTest { @Test public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception { - final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); mTestLooper.dispatchAll(); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList(); mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); mTestLooper.dispatchAll(); - verify(mCallback).onNewSnapshot( - eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet()))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap()))); } @Test public void testSlotClearedAfterValidTriggersCallbacks() throws Exception { - final Set activeSubGroups = Collections.singleton(TEST_PARCEL_UUID); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); mTestLooper.dispatchAll(); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); mTestLooper.dispatchAll(); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(Collections.emptySet()))); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap()))); assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); } + @Test + public void testChangingPrivilegedPackagesAfterValidTriggersCallbacks() throws Exception { + setupReadySubIds(); + + // Setup initial "valid" state + final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); + listener.onSubscriptionsChanged(); + mTestLooper.dispatchAll(); + + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); + + // Simulate a loss of carrier privileges + setPrivilegedPackagesForMock(Collections.emptyList()); + listener.onSubscriptionsChanged(); + mTestLooper.dispatchAll(); + + verify(mCallback) + .onNewSnapshot( + eq(buildExpectedSnapshot(singletonMap(TEST_PARCEL_UUID, emptySet())))); + } + @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -324,7 +380,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), From a75dc41bff0eff58462e8f0018cddd326f05d678 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 1 Dec 2020 17:39:50 -0800 Subject: [PATCH 0024/1057] Pull VcnNetworkProvider out into a separate class This change makes the VcnNetworkProvider a separate class, and caches all NetworkRequest(s) to ensure that VcnTunnel(s) satisfy all requests that they can accept. Bug: 163431879 Test: atest FrameworksVcnTests Change-Id: I3b7695628d0153a33f7e7f40d839df1463d58b07 --- .../android/server/VcnManagementService.java | 26 +-- .../src/com/android/server/vcn/Vcn.java | 149 ++++++++++++++++-- .../com/android/server/vcn/VcnContext.java | 2 - .../server/vcn/VcnGatewayConnection.java | 4 +- .../server/vcn/VcnNetworkProvider.java | 108 +++++++++++++ .../server/VcnManagementServiceTest.java | 7 +- .../server/vcn/VcnNetworkProviderTest.java | 121 ++++++++++++++ 7 files changed, 377 insertions(+), 40 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 77e8e96a51..c191a78aad 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -25,8 +25,6 @@ import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; -import android.net.NetworkProvider; -import android.net.NetworkRequest; import android.net.vcn.IVcnManagementService; import android.net.vcn.VcnConfig; import android.os.Binder; @@ -50,6 +48,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; import java.io.IOException; @@ -390,6 +389,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active + // VCN. + final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config); mVcns.put(subscriptionGroup, newInstance); } @@ -493,24 +495,4 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Collections.unmodifiableMap(mVcns); } } - - /** - * Network provider for VCN networks. - * - * @hide - */ - public class VcnNetworkProvider extends NetworkProvider { - VcnNetworkProvider(Context context, Looper looper) { - super(context, looper, VcnNetworkProvider.class.getSimpleName()); - } - - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { - synchronized (mLock) { - for (Vcn instance : mVcns.values()) { - instance.onNetworkRequested(request, score, providerId); - } - } - } - } } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 493761be62..9d21b9241c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -16,32 +16,69 @@ package com.android.server.vcn; + import android.annotation.NonNull; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfig; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; +import android.util.Slog; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; /** * Represents an single instance of a VCN. * - *

    Each Vcn instance manages all tunnels for a given subscription group, including per-capability - * networks, network selection, and multi-homing. + *

    Each Vcn instance manages all {@link VcnGatewayConnection}(s) for a given subscription group, + * including per-capability networks, network selection, and multi-homing. * * @hide */ public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); + private static final int MSG_EVENT_BASE = 0; + private static final int MSG_CMD_BASE = 100; + + /** + * A carrier app updated the configuration. + * + *

    Triggers update of config, re-evaluating all active and underlying networks. + * + * @param obj VcnConfig + */ + private static final int MSG_EVENT_CONFIG_UPDATED = MSG_EVENT_BASE; + + /** + * A NetworkRequest was added or updated. + * + *

    Triggers an evaluation of all active networks, bringing up a new one if necessary. + * + * @param obj NetworkRequest + */ + private static final int MSG_EVENT_NETWORK_REQUESTED = MSG_EVENT_BASE + 1; + + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ + private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Dependencies mDeps; + @NonNull private final VcnNetworkRequestListener mRequestListener; + + @NonNull + private final Map mVcnGatewayConnections = + new HashMap<>(); @NonNull private VcnConfig mConfig; + private boolean mIsRunning = true; + public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @@ -58,31 +95,123 @@ public class Vcn extends Handler { mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mDeps = Objects.requireNonNull(deps, "Missing deps"); + mRequestListener = new VcnNetworkRequestListener(); mConfig = Objects.requireNonNull(config, "Missing config"); + + // Register to receive cached and future NetworkRequests + mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } /** Asynchronously updates the configuration and triggers a re-evaluation of Networks */ public void updateConfig(@NonNull VcnConfig config) { Objects.requireNonNull(config, "Missing config"); - // TODO: Proxy to handler, and make config there. + + sendMessage(obtainMessage(MSG_EVENT_CONFIG_UPDATED, config)); } - /** Asynchronously tears down this Vcn instance, along with all tunnels and Networks */ + /** Asynchronously tears down this Vcn instance, including VcnGatewayConnection(s) */ public void teardownAsynchronously() { - // TODO: Proxy to handler, and teardown there. + sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); } - /** Notifies this Vcn instance of a new NetworkRequest */ - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { - Objects.requireNonNull(request, "Missing request"); + private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + Objects.requireNonNull(request, "Missing request"); - // TODO: Proxy to handler, and handle there. + sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request)); + } } @Override public void handleMessage(@NonNull Message msg) { - // TODO: Do something + if (!mIsRunning) { + return; + } + + switch (msg.what) { + case MSG_EVENT_CONFIG_UPDATED: + handleConfigUpdated((VcnConfig) msg.obj); + break; + case MSG_EVENT_NETWORK_REQUESTED: + handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + case MSG_CMD_TEARDOWN: + handleTeardown(); + break; + default: + Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); + } + } + + private void handleConfigUpdated(@NonNull VcnConfig config) { + // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode() + Slog.v(getLogTag(), String.format("Config updated: config = %s", config.hashCode())); + + mConfig = config; + + // TODO: Reevaluate active VcnGatewayConnection(s) + } + + private void handleTeardown() { + mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener); + + for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { + gatewayConnection.teardownAsynchronously(); + } + + mIsRunning = false; + } + + private void handleNetworkRequested( + @NonNull NetworkRequest request, int score, int providerId) { + if (score > getNetworkScore()) { + Slog.v(getLogTag(), + "Request " + request.requestId + " already satisfied by higher-scoring (" + + score + ") network from provider " + providerId); + return; + } + + // If preexisting VcnGatewayConnection(s) satisfy request, return + for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { + if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + Slog.v(getLogTag(), + "Request " + request.requestId + + " satisfied by existing VcnGatewayConnection"); + return; + } + } + + // If any supported (but not running) VcnGatewayConnection(s) can satisfy request, bring it + // up + for (VcnGatewayConnectionConfig gatewayConnectionConfig : + mConfig.getGatewayConnectionConfigs()) { + if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + Slog.v( + getLogTag(), + "Bringing up new VcnGatewayConnection for request " + request.requestId); + + final VcnGatewayConnection vcnGatewayConnection = + new VcnGatewayConnection( + mVcnContext, mSubscriptionGroup, gatewayConnectionConfig); + mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); + } + } + } + + private boolean requestSatisfiedByGatewayConnectionConfig( + @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { + final NetworkCapabilities configCaps = new NetworkCapabilities(); + for (int cap : config.getAllExposedCapabilities()) { + configCaps.addCapability(cap); + } + + return request.networkCapabilities.satisfiedByNetworkCapabilities(configCaps); + } + + private String getLogTag() { + return String.format("%s [%d]", TAG, mSubscriptionGroup.hashCode()); } /** Retrieves the network score for a VCN Network */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 8ab52931ca..dba59bdbee 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -20,8 +20,6 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Looper; -import com.android.server.VcnManagementService.VcnNetworkProvider; - import java.util.Objects; /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 49c9b3297c..7ea8e04580 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -65,8 +65,8 @@ public class VcnGatewayConnection extends Handler implements UnderlyingNetworkTr mDeps.newUnderlyingNetworkTracker(mVcnContext, subscriptionGroup, this); } - /** Tears down this GatewayConnection, and any resources used */ - public void teardown() { + /** Asynchronously tears down this GatewayConnection, and any resources used */ + public void teardownAsynchronously() { mUnderlyingNetworkTracker.teardown(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java new file mode 100644 index 0000000000..7f5b23c9db --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -0,0 +1,108 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.NetworkProvider; +import android.net.NetworkRequest; +import android.os.Looper; +import android.util.ArraySet; +import android.util.Slog; +import android.util.SparseArray; + +import java.util.Objects; +import java.util.Set; + +/** + * VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed. + * + *

    The VcnNetworkProvider provides a caching layer to ensure that all listeners receive all + * active NetworkRequest(s), including ones that were filed prior to listener registration. + * + * @hide + */ +public class VcnNetworkProvider extends NetworkProvider { + private static final String TAG = VcnNetworkProvider.class.getSimpleName(); + + private final Set mListeners = new ArraySet<>(); + private final SparseArray mRequests = new SparseArray<>(); + + public VcnNetworkProvider(Context context, Looper looper) { + super(context, looper, VcnNetworkProvider.class.getSimpleName()); + } + + // Package-private + void registerListener(@NonNull NetworkRequestListener listener) { + mListeners.add(listener); + + // Send listener all cached requests + for (int i = 0; i < mRequests.size(); i++) { + notifyListenerForEvent(listener, mRequests.valueAt(i)); + } + } + + // Package-private + void unregisterListener(@NonNull NetworkRequestListener listener) { + mListeners.remove(listener); + } + + private void notifyListenerForEvent( + @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { + listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); + } + + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + Slog.v( + TAG, + String.format( + "Network requested: Request = %s, score = %d, providerId = %d", + request, score, providerId)); + + final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId); + mRequests.put(request.requestId, entry); + + // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on + // Default Data Sub, or similar) + for (NetworkRequestListener listener : mListeners) { + notifyListenerForEvent(listener, entry); + } + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + mRequests.remove(request.requestId); + } + + private static class NetworkRequestEntry { + public final NetworkRequest mRequest; + public final int mScore; + public final int mProviderId; + + private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) { + mRequest = Objects.requireNonNull(request, "Missing request"); + mScore = score; + mProviderId = providerId; + } + } + + // package-private + interface NetworkRequestListener { + void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index d2caa8f0be..696110f018 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -49,10 +49,10 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.VcnManagementService.VcnNetworkProvider; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; import org.junit.Test; @@ -191,8 +191,7 @@ public class VcnManagementServiceTest { public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); - verify(mConnMgr) - .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class)); + verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); } @@ -309,7 +308,7 @@ public class VcnManagementServiceTest { // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new // vcnInstance. mTestLooper.moveTimeForward( - VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS - 1); + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java new file mode 100644 index 0000000000..c2c6200fd5 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -0,0 +1,121 @@ +/* + * 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.vcn; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +/** Tests for TelephonySubscriptionTracker */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnNetworkProviderTest { + private static final int TEST_SCORE_UNSATISFIED = 0; + private static final int TEST_SCORE_HIGH = 100; + private static final int TEST_PROVIDER_ID = 1; + private static final int TEST_LEGACY_TYPE = ConnectivityManager.TYPE_MOBILE; + private static final NetworkRequest.Type TEST_REQUEST_TYPE = NetworkRequest.Type.REQUEST; + + @NonNull private final Context mContext; + @NonNull private final TestLooper mTestLooper; + + @NonNull private VcnNetworkProvider mVcnNetworkProvider; + @NonNull private NetworkRequestListener mListener; + + public VcnNetworkProviderTest() { + mContext = mock(Context.class); + mTestLooper = new TestLooper(); + } + + @Before + public void setUp() throws Exception { + mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper()); + mListener = mock(NetworkRequestListener.class); + } + + @Test + public void testRequestsPassedToRegisteredListeners() throws Exception { + mVcnNetworkProvider.registerListener(mListener); + + final NetworkRequest request = mock(NetworkRequest.class); + mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + } + + @Test + public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider() + throws Exception { + mVcnNetworkProvider.registerListener(mListener); + + final NetworkRequest request = mock(NetworkRequest.class); + mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); + verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); + } + + @Test + public void testUnregisterListener() throws Exception { + mVcnNetworkProvider.registerListener(mListener); + mVcnNetworkProvider.unregisterListener(mListener); + + final NetworkRequest request = mock(NetworkRequest.class); + mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verifyNoMoreInteractions(mListener); + } + + @Test + public void testCachedRequestsPassedOnRegister() throws Exception { + final List requests = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + final NetworkRequest request = + new NetworkRequest( + new NetworkCapabilities(), + TEST_LEGACY_TYPE, + i /* requestId */, + TEST_REQUEST_TYPE); + + requests.add(request); + mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); + } + + mVcnNetworkProvider.registerListener(mListener); + for (int i = 0; i < requests.size(); i++) { + final NetworkRequest request = requests.get(i); + verify(mListener).onNetworkRequested(request, i, i + 1); + } + verifyNoMoreInteractions(mListener); + } +} From 40e44b702f7709360e0bfcc13553c0f00cea9056 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 21 Sep 2020 11:34:47 -0700 Subject: [PATCH 0025/1057] Add VcnGatewayConnection state skeleton, signals and fields This change adds the basic signals and fields required for VcnGatewayConnection management. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: Iae187c0be38e9b85b8830c56f751df52b5afb7bc --- .../server/vcn/VcnGatewayConnection.java | 571 +++++++++++++++++- 1 file changed, 563 insertions(+), 8 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 7ea8e04580..e88ce56d07 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -16,33 +16,411 @@ package com.android.server.vcn; +import static com.android.server.VcnManagementService.VDBG; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.IpSecManager; +import android.net.IpSecManager.IpSecTunnelInterface; +import android.net.IpSecManager.ResourceUnavailableException; +import android.net.IpSecTransform; +import android.net.Network; +import android.net.NetworkAgent; +import android.net.annotations.PolicyDirection; +import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeSession; import android.net.vcn.VcnGatewayConnectionConfig; -import android.os.Handler; +import android.os.Message; import android.os.ParcelUuid; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; +import java.io.IOException; +import java.net.InetAddress; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * A single VCN Gateway Connection, providing a single public-facing VCN network. * *

    This class handles mobility events, performs retries, and tracks safe-mode conditions. * + *

    Internal state transitions are as follows:
    + *
    + * +----------------------------+                 +------------------------------+
    + * |     DisconnectedState      |    Teardown or  |      DisconnectingState      |
    + * |                            |<--no available--|                              |
    + * |       Initial state.       |    underlying   | Transitive state for tearing |
    + * +----------------------------+     networks    | tearing down an IKE session. |
    + *               |                                +------------------------------+
    + *               |                                         ^          |
    + *       Underlying Network            Teardown requested  |   Not tearing down
    + *            changed               +--or retriable error--+  and has available
    + *               |                  |      occurred           underlying network
    + *               |                  ^                                 |
    + *               v                  |                                 v
    + * +----------------------------+   |             +------------------------------+
    + * |      ConnectingState       |<----------------|      RetryTimeoutState       |
    + * |                            |   |             |                              |
    + * |    Transitive state for    |   |             |     Transitive state for     |
    + * |  starting IKE negotiation. |---+             |  handling retriable errors.  |
    + * +----------------------------+   |             +------------------------------+
    + *               |                  |
    + *          IKE session             |
    + *           negotiated             |
    + *               |                  |
    + *               v                  |
    + * +----------------------------+   ^
    + * |      ConnectedState        |   |
    + * |                            |   |
    + * |     Stable state where     |   |
    + * |  gateway connection is set |   |
    + * | up, and Android Network is |   |
    + * |         connected.         |---+
    + * +----------------------------+
    + * 
    + * * @hide */ -public class VcnGatewayConnection extends Handler implements UnderlyingNetworkTrackerCallback { +public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); + private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE; + + private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: "; + private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = + "Underlying Network lost"; + private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; + private static final int TOKEN_ANY = Integer.MIN_VALUE; + + private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; + private static final int TEARDOWN_TIMEOUT_SECONDS = 5; + + private interface EventInfo {} + + /** + * Sent when there are changes to the underlying network (per the UnderlyingNetworkTracker). + * + *

    May indicate an entirely new underlying network, OR a change in network properties. + * + *

    Relevant in ALL states. + * + *

    In the Connected state, this MAY indicate a mobility even occurred. + * + * @param arg1 The "any" token; this event is always applicable. + * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. + */ + private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; + + private static class EventUnderlyingNetworkChangedInfo implements EventInfo { + @Nullable public final UnderlyingNetworkRecord newUnderlying; + + EventUnderlyingNetworkChangedInfo(@Nullable UnderlyingNetworkRecord newUnderlying) { + this.newUnderlying = newUnderlying; + } + + @Override + public int hashCode() { + return Objects.hash(newUnderlying); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventUnderlyingNetworkChangedInfo)) { + return false; + } + + final EventUnderlyingNetworkChangedInfo rhs = (EventUnderlyingNetworkChangedInfo) other; + return Objects.equals(newUnderlying, rhs.newUnderlying); + } + } + + /** + * Sent (delayed) to trigger an attempt to reestablish the tunnel. + * + *

    Only relevant in the Retry-timeout state, discarded in all other states. + * + *

    Upon receipt of this signal, the state machine will transition from the Retry-timeout + * state to the Connecting state. + * + * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState. + */ + private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; + + /** + * Sent when a gateway connection has been lost, either due to a IKE or child failure. + * + *

    Relevant in all states that have an IKE session. + * + *

    Upon receipt of this signal, the state machine will (unless loss of the session is + * expected) transition to the Disconnecting state, to ensure IKE session closure before + * retrying, or fully shutting down. + * + * @param arg1 The session token for the IKE Session that was lost, used to prevent out-of-date + * signals from propagating. + * @param obj @NonNull An EventSessionLostInfo instance with relevant data. + */ + private static final int EVENT_SESSION_LOST = 3; + + private static class EventSessionLostInfo implements EventInfo { + @Nullable public final Exception exception; + + EventSessionLostInfo(@NonNull Exception exception) { + this.exception = exception; + } + + @Override + public int hashCode() { + return Objects.hash(exception); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventSessionLostInfo)) { + return false; + } + + final EventSessionLostInfo rhs = (EventSessionLostInfo) other; + return Objects.equals(exception, rhs.exception); + } + } + + /** + * Sent when an IKE session has completely closed. + * + *

    Relevant only in the Disconnecting State, used to identify that a session being torn down + * was fully closed. If this event is not fired within a timely fashion, the IKE session will be + * forcibly terminated. + * + *

    Upon receipt of this signal, the state machine will (unless closure of the session is + * expected) transition to the Disconnected or RetryTimeout states, depending on whether the + * GatewayConnection is being fully torn down. + * + * @param arg1 The session token for the IKE Session that was lost, used to prevent out-of-date + * signals from propagating. + * @param obj @NonNull An EventSessionLostInfo instance with relevant data. + */ + private static final int EVENT_SESSION_CLOSED = 4; + + /** + * Sent when an IKE Child Transform was created, and should be applied to the tunnel. + * + *

    Only relevant in the Connecting, Connected and Migrating states. This callback MUST be + * handled in the Connected or Migrating states, and should be deferred if necessary. + * + * @param arg1 The session token for the IKE Session that had a new child created, used to + * prevent out-of-date signals from propagating. + * @param obj @NonNull An EventTransformCreatedInfo instance with relevant data. + */ + private static final int EVENT_TRANSFORM_CREATED = 5; + + private static class EventTransformCreatedInfo implements EventInfo { + @PolicyDirection public final int direction; + @NonNull public final IpSecTransform transform; + + EventTransformCreatedInfo( + @PolicyDirection int direction, @NonNull IpSecTransform transform) { + this.direction = direction; + this.transform = Objects.requireNonNull(transform); + } + + @Override + public int hashCode() { + return Objects.hash(direction, transform); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventTransformCreatedInfo)) { + return false; + } + + final EventTransformCreatedInfo rhs = (EventTransformCreatedInfo) other; + return direction == rhs.direction && Objects.equals(transform, rhs.transform); + } + } + + /** + * Sent when an IKE Child Session was completely opened and configured successfully. + * + *

    Only relevant in the Connected and Migrating states. + * + * @param arg1 The session token for the IKE Session for which a child was opened and configured + * successfully, used to prevent out-of-date signals from propagating. + * @param obj @NonNull An EventSetupCompletedInfo instance with relevant data. + */ + private static final int EVENT_SETUP_COMPLETED = 6; + + private static class EventSetupCompletedInfo implements EventInfo { + @NonNull public final ChildSessionConfiguration childSessionConfig; + + EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) { + this.childSessionConfig = Objects.requireNonNull(childSessionConfig); + } + + @Override + public int hashCode() { + return Objects.hash(childSessionConfig); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventSetupCompletedInfo)) { + return false; + } + + final EventSetupCompletedInfo rhs = (EventSetupCompletedInfo) other; + return Objects.equals(childSessionConfig, rhs.childSessionConfig); + } + } + + /** + * Sent when conditions (internal or external) require a disconnect. + * + *

    Relevant in all states except the Disconnected state. + * + *

    This signal is often fired with a timeout in order to prevent disconnecting during + * transient conditions, such as network switches. Upon the transient passing, the signal is + * canceled based on the disconnect reason. + * + *

    Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel + * any pending work items, and move to the Disconnected state. + * + * @param arg1 The "any" token; this signal is always honored. + * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. + */ + private static final int EVENT_DISCONNECT_REQUESTED = 7; + + private static class EventDisconnectRequestedInfo implements EventInfo { + /** The reason why the disconnect was requested. */ + @NonNull public final String reason; + + EventDisconnectRequestedInfo(@NonNull String reason) { + this.reason = Objects.requireNonNull(reason); + } + + @Override + public int hashCode() { + return Objects.hash(reason); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventDisconnectRequestedInfo)) { + return false; + } + + final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; + return reason.equals(rhs.reason); + } + } + + /** + * Sent (delayed) to trigger a forcible close of an IKE session. + * + *

    Only relevant in the Disconnecting state, discarded in all other states. + * + *

    Upon receipt of this signal, the state machine will transition from the Disconnecting + * state to the Disconnected state. + * + * @param arg1 The session token for the IKE Session that is being torn down, used to prevent + * out-of-date signals from propagating. + */ + private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8; + + @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState(); + @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState(); + @NonNull private final ConnectingState mConnectingState = new ConnectingState(); + @NonNull private final ConnectedState mConnectedState = new ConnectedState(); + @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; @NonNull private final Dependencies mDeps; + @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; + + @NonNull private final IpSecManager mIpSecManager; + @NonNull private final IpSecTunnelInterface mTunnelIface; + + /** Running state of this VcnGatewayConnection. */ + private boolean mIsRunning = true; + + /** + * The token used by the primary/current/active session. + * + *

    This token MUST be updated when a new stateful/async session becomes the + * primary/current/active session. Example cases where the session changes are: + * + *

      + *
    • Switching to an IKE session as the primary session + *
    + * + *

    In the migrating state, where two sessions may be active, this value MUST represent the + * primary session. This is USUALLY the existing session, and is only switched to the new + * session when: + * + *

      + *
    • The new session connects successfully, and becomes the primary session + *
    • The existing session is lost, and the remaining (new) session becomes the primary + * session + *
    + */ + private int mCurrentToken = -1; + + /** + * The next usable token. + * + *

    A new token MUST be used for all new IKE sessions. + */ + private int mNextToken = 0; + + /** + * The number of unsuccessful attempts since the last successful connection. + * + *

    This number MUST be incremented each time the RetryTimeout state is entered, and cleared + * each time the Connected state is entered. + */ + private int mFailedAttempts = 0; + + /** + * The current underlying network. + * + *

    Set in any states, always @NonNull in all states except Disconnected, null otherwise. + */ + private UnderlyingNetworkRecord mUnderlying; + + /** + * The active IKE session. + * + *

    Set in Connecting or Migrating States, always @NonNull in Connecting, Connected, and + * Migrating states, null otherwise. + */ + private IkeSession mIkeSession; + + /** + * The last known child configuration. + * + *

    Set in Connected and Migrating states, always @NonNull in Connected, Migrating + * states, @Nullable otherwise. + */ + private ChildSessionConfiguration mChildConfig; + + /** + * The active network agent. + * + *

    Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable + * otherwise. + */ + private NetworkAgent mNetworkAgent; + public VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @@ -55,19 +433,199 @@ public class VcnGatewayConnection extends Handler implements UnderlyingNetworkTr @NonNull ParcelUuid subscriptionGroup, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull Dependencies deps) { - super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); + super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); mDeps = Objects.requireNonNull(deps, "Missing deps"); + mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback(); + mUnderlyingNetworkTracker = - mDeps.newUnderlyingNetworkTracker(mVcnContext, subscriptionGroup, this); + mDeps.newUnderlyingNetworkTracker( + mVcnContext, subscriptionGroup, mUnderlyingNetworkTrackerCallback); + mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); + + IpSecTunnelInterface iface; + try { + iface = + mIpSecManager.createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, new Network(-1)); + } catch (IOException | ResourceUnavailableException e) { + teardownAsynchronously(); + mTunnelIface = null; + + return; + } + + mTunnelIface = iface; + + addState(mDisconnectedState); + addState(mDisconnectingState); + addState(mConnectingState); + addState(mConnectedState); + addState(mRetryTimeoutState); + + setInitialState(mDisconnectedState); + setDbg(VDBG); + start(); } - /** Asynchronously tears down this GatewayConnection, and any resources used */ + /** + * Asynchronously tears down this GatewayConnection, and any resources used. + * + *

    Once torn down, this VcnTunnel CANNOT be started again. + */ public void teardownAsynchronously() { mUnderlyingNetworkTracker.teardown(); + + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. + if (mTunnelIface != null) { + mTunnelIface.close(); + } + + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ANY, + new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); + quit(); + + // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this + // is also called asynchronously when a NetworkAgent becomes unwanted + } + + private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { + @Override + public void onSelectedUnderlyingNetworkChanged( + @Nullable UnderlyingNetworkRecord underlying) { + // If underlying is null, all underlying networks have been lost. Disconnect VCN after a + // timeout. + if (underlying == null) { + sendMessageDelayed( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ANY, + new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), + TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); + return; + } + + // Cancel any existing disconnect due to loss of underlying network + // getHandler() can return null if the state machine has already quit. Since this is + // called + // from other classes, this condition must be verified. + if (getHandler() != null) { + getHandler() + .removeEqualMessages( + EVENT_DISCONNECT_REQUESTED, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + } + sendMessage( + EVENT_UNDERLYING_NETWORK_CHANGED, + TOKEN_ANY, + new EventUnderlyingNetworkChangedInfo(underlying)); + } + } + + private void sendMessage(int what, int token, EventInfo data) { + super.sendMessage(what, token, ARG_NOT_PRESENT, data); + } + + private void sendMessage(int what, int token, int arg2, EventInfo data) { + super.sendMessage(what, token, arg2, data); + } + + private void sendMessageDelayed(int what, int token, EventInfo data, long timeout) { + super.sendMessageDelayed(what, token, ARG_NOT_PRESENT, data, timeout); + } + + private void sendMessageDelayed(int what, int token, int arg2, EventInfo data, long timeout) { + super.sendMessageDelayed(what, token, arg2, data, timeout); + } + + private void sessionLost(int token, @Nullable Exception exception) { + sendMessage(EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); + } + + private void sessionClosed(int token, @Nullable Exception exception) { + // SESSION_LOST MUST be sent before SESSION_CLOSED to ensure that the SM moves to the + // Disconnecting state. + sessionLost(token, exception); + sendMessage(EVENT_SESSION_CLOSED, token); + } + + private void childTransformCreated( + int token, @NonNull IpSecTransform transform, int direction) { + sendMessage( + EVENT_TRANSFORM_CREATED, + token, + new EventTransformCreatedInfo(direction, transform)); + } + + private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) { + sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig)); + } + + private abstract class BaseState extends State { + protected void enterState() throws Exception {} + + protected abstract void processStateMsg(Message msg) throws Exception; + } + /** + * State representing the a disconnected VCN tunnel. + * + *

    This is also is the initial state. + */ + private class DisconnectedState extends BaseState { + @Override + protected void processStateMsg(Message msg) {} + } + + private abstract class ActiveBaseState extends BaseState {} + + /** + * Transitive state representing a VCN that is tearing down an IKE session. + * + *

    In this state, the IKE session is in the process of being torn down. If the IKE session + * does not complete teardown in a timely fashion, it will be killed (forcibly closed). + */ + private class DisconnectingState extends ActiveBaseState { + @Override + protected void processStateMsg(Message msg) {} + } + + /** + * Transitive state representing a VCN that is making an primary (non-handover) connection. + * + *

    This state starts IKE negotiation, but defers transform application & network setup to the + * Connected state. + */ + private class ConnectingState extends ActiveBaseState { + @Override + protected void processStateMsg(Message msg) {} + } + + private abstract class ConnectedStateBase extends ActiveBaseState {} + + /** + * Stable state representing a VCN that has a functioning connection to the mobility anchor. + * + *

    This state handles IPsec transform application (initial and rekey), NetworkAgent setup, + * and monitors for mobility events. + */ + class ConnectedState extends ConnectedStateBase { + @Override + protected void processStateMsg(Message msg) {} + } + + /** + * Transitive state representing a VCN that failed to establish a connection, and will retry. + * + *

    This state will be exited upon a new underlying network being found, or timeout expiry. + */ + class RetryTimeoutState extends ActiveBaseState { + @Override + protected void processStateMsg(Message msg) {} } private static class Dependencies { @@ -78,7 +636,4 @@ public class VcnGatewayConnection extends Handler implements UnderlyingNetworkTr return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback); } } - - @Override - public void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying) {} } From 8ad462da9de864b891ac7861504240d31b9317d4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Oct 2020 17:34:12 -0700 Subject: [PATCH 0026/1057] Add utility methods for creation of NetInfo, NetCaps, and LinkProps This change adds basic utility methods to create network info, network capabilities and link properties Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I915e0c4e9ca989344b9a4785e200381db0b94fb8 --- .../server/vcn/VcnGatewayConnection.java | 172 +++++++++++++++++- Vcn/tests/unit/Android.bp | 1 + .../vcn/VcnGatewayConnectionConfigTest.java | 13 +- .../server/vcn/VcnGatewayConnectionTest.java | 82 +++++++++ 4 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index e88ce56d07..7024e67a82 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -16,30 +16,57 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.ConnectivityManager; import android.net.InetAddresses; +import android.net.IpPrefix; import android.net.IpSecManager; import android.net.IpSecManager.IpSecTunnelInterface; import android.net.IpSecManager.ResourceUnavailableException; import android.net.IpSecTransform; +import android.net.LinkAddress; +import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.RouteInfo; import android.net.annotations.PolicyDirection; +import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeSession; +import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; +import android.telephony.TelephonyManager; +import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -628,12 +655,155 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} } - private static class Dependencies { + // TODO: Remove this when migrating to new NetworkAgent API + private static NetworkInfo buildNetworkInfo(boolean isConnected) { + NetworkInfo info = + new NetworkInfo( + ConnectivityManager.TYPE_MOBILE, + TelephonyManager.NETWORK_TYPE_UNKNOWN, + "MOBILE", + "VCN"); + info.setDetailedState( + isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null); + + return info; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static NetworkCapabilities buildNetworkCapabilities( + @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { + final NetworkCapabilities caps = new NetworkCapabilities(); + + caps.addTransportType(TRANSPORT_CELLULAR); + caps.addCapability(NET_CAPABILITY_NOT_CONGESTED); + caps.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + + // Add exposed capabilities + for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) { + caps.addCapability(cap); + } + + return caps; + } + + private static LinkProperties buildConnectedLinkProperties( + @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull ChildSessionConfiguration childConfig) { + final LinkProperties lp = new LinkProperties(); + + lp.setInterfaceName(tunnelIface.getInterfaceName()); + for (LinkAddress addr : childConfig.getInternalAddresses()) { + lp.addLinkAddress(addr); + } + for (InetAddress addr : childConfig.getInternalDnsServers()) { + lp.addDnsServer(addr); + } + + lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + + lp.setMtu(gatewayConnectionConfig.getMaxMtu()); + + return lp; + } + + private class IkeSessionCallbackImpl implements IkeSessionCallback { + private final int mToken; + + IkeSessionCallbackImpl(int token) { + mToken = token; + } + + @Override + public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { + Slog.v(TAG, "IkeOpened for token " + mToken); + // Nothing to do here. + } + + @Override + public void onClosed() { + Slog.v(TAG, "IkeClosed for token " + mToken); + sessionClosed(mToken, null); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception); + sessionClosed(mToken, exception); + } + + @Override + public void onError(@NonNull IkeProtocolException exception) { + Slog.v(TAG, "IkeError for token " + mToken, exception); + // Non-fatal, log and continue. + } + } + + private class ChildSessionCallbackImpl implements ChildSessionCallback { + private final int mToken; + + ChildSessionCallbackImpl(int token) { + mToken = token; + } + + @Override + public void onOpened(@NonNull ChildSessionConfiguration childConfig) { + Slog.v(TAG, "ChildOpened for token " + mToken); + childOpened(mToken, childConfig); + } + + @Override + public void onClosed() { + Slog.v(TAG, "ChildClosed for token " + mToken); + sessionLost(mToken, null); + } + + @Override + public void onClosedExceptionally(@NonNull IkeException exception) { + Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception); + sessionLost(mToken, exception); + } + + @Override + public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) { + Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken); + childTransformCreated(mToken, transform, direction); + } + + @Override + public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) { + // Nothing to be done; no references to the IpSecTransform are held, and this transform + // will be closed by the IKE library. + Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); + } + } + + /** External dependencies used by VcnGatewayConnection, for injection in tests. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Builds a new UnderlyingNetworkTracker. */ public UnderlyingNetworkTracker newUnderlyingNetworkTracker( VcnContext vcnContext, ParcelUuid subscriptionGroup, UnderlyingNetworkTrackerCallback callback) { return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback); } + + /** Builds a new IkeSession. */ + public IkeSession newIkeSession( + VcnContext vcnContext, + IkeSessionParams ikeSessionParams, + ChildSessionParams childSessionParams, + IkeSessionCallback ikeSessionCallback, + ChildSessionCallback childSessionCallback) { + return new IkeSession( + vcnContext.getContext(), + ikeSessionParams, + childSessionParams, + new HandlerExecutor(new Handler(vcnContext.getLooper())), + ikeSessionCallback, + childSessionCallback); + } } } diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index f967bf0d8f..3c08d347b1 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -20,6 +20,7 @@ android_test { "services.core", ], libs: [ + "android.net.ipsec.ike.stubs.module_lib", "android.test.runner", "android.test.base", "android.test.mock", diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index e98b6ef2b3..dfd0c8a751 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -33,12 +33,13 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionConfigTest { - private static final int[] EXPOSED_CAPS = + // Public for use in VcnGatewayConnectionTest + public static final int[] EXPOSED_CAPS = new int[] { NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS }; - private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; - private static final long[] RETRY_INTERVALS_MS = + public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + public static final long[] RETRY_INTERVALS_MS = new long[] { TimeUnit.SECONDS.toMillis(5), TimeUnit.SECONDS.toMillis(30), @@ -47,10 +48,10 @@ public class VcnGatewayConnectionConfigTest { TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(30) }; - private static final int MAX_MTU = 1360; + public static final int MAX_MTU = 1360; - // Package protected for use in VcnConfigTest - static VcnGatewayConnectionConfig buildTestConfig() { + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfig() { final VcnGatewayConnectionConfig.Builder builder = new VcnGatewayConnectionConfig.Builder() .setRetryInterval(RETRY_INTERVALS_MS) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java new file mode 100644 index 0000000000..d741e5cf4b --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -0,0 +1,82 @@ +/* + * 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.vcn; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.os.ParcelUuid; +import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** Tests for TelephonySubscriptionTracker */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionTest { + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); + private static final int TEST_SIM_SLOT_INDEX = 1; + private static final int TEST_SUBSCRIPTION_ID_1 = 2; + private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); + private static final int TEST_SUBSCRIPTION_ID_2 = 3; + private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); + private static final Map TEST_SUBID_TO_GROUP_MAP; + + static { + final Map subIdToGroupMap = new HashMap<>(); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID); + TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); + } + + @NonNull private final Context mContext; + @NonNull private final TestLooper mTestLooper; + @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + @NonNull private final VcnGatewayConnection.Dependencies mDeps; + + public VcnGatewayConnectionTest() { + mContext = mock(Context.class); + mTestLooper = new TestLooper(); + mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mDeps = mock(VcnGatewayConnection.Dependencies.class); + } + + @Test + public void testBuildNetworkCapabilities() throws Exception { + final NetworkCapabilities caps = + VcnGatewayConnection.buildNetworkCapabilities( + VcnGatewayConnectionConfigTest.buildTestConfig()); + + for (int exposedCapability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + assertTrue(caps.hasCapability(exposedCapability)); + } + } +} From a04ef08158247dc95dc86ce277506df0d9eb347b Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 11 Jan 2021 14:46:46 -0800 Subject: [PATCH 0027/1057] Define VcnTransportInfo. This CL defines VcnTransportInfo - a TransportInfo to be used for top-level VCN Networks registered with ConnectivityService. Bug: 177261675 Test: atest FrameworksVcnTests Change-Id: I66e9a0bf73c6e42eb5aa7fd39463fdfed483ecfa --- .../src/android/net/vcn/VcnTransportInfo.java | 125 ++++++++++++++++++ .../android/net/vcn/VcnTransportInfoTest.java | 71 ++++++++++ 2 files changed, 196 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java new file mode 100644 index 0000000000..4d8cf91621 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -0,0 +1,125 @@ +/* + * 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 android.net.vcn; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.TransportInfo; +import android.net.wifi.WifiInfo; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.SubscriptionManager; + +import java.util.Objects; + +/** + * VcnTransportInfo contains information about the VCN's underlying transports for SysUi. + * + *

    Presence of this class in the NetworkCapabilities.TransportInfo implies that the network is a + * VCN. + * + *

    VcnTransportInfo must exist on top of either an underlying Wifi or Cellular Network. If the + * underlying Network is WiFi, the subId will be {@link + * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo + * will be {@code null}. + * + * @hide + */ +public class VcnTransportInfo implements TransportInfo, Parcelable { + @Nullable private final WifiInfo mWifiInfo; + private final int mSubId; + + public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { + this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + public VcnTransportInfo(int subId) { + this(null /* wifiInfo */, subId); + } + + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { + if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + throw new IllegalArgumentException( + "VcnTransportInfo requires either non-null WifiInfo or valid subId"); + } + + mWifiInfo = wifiInfo; + mSubId = subId; + } + + /** + * Get the {@link WifiInfo} for this VcnTransportInfo. + * + *

    If the underlying Network for the associated VCN is Cellular, returns null. + * + * @return the WifiInfo if there is an underlying WiFi connection, else null. + */ + @Nullable + public WifiInfo getWifiInfo() { + return mWifiInfo; + } + + /** + * Get the subId for the VCN Network associated with this VcnTransportInfo. + * + *

    If the underlying Network for the associated VCN is WiFi, returns {@link + * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * + * @return the Subscription ID if a cellular underlying Network is present, else {@link + * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}. + */ + public int getSubId() { + return mSubId; + } + + @Override + public int hashCode() { + return Objects.hash(mWifiInfo, mSubId); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof VcnTransportInfo)) return false; + final VcnTransportInfo that = (VcnTransportInfo) o; + + return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) {} + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public VcnTransportInfo createFromParcel(Parcel in) { + // return null instead of a default VcnTransportInfo to avoid leaking + // information about this being a VCN Network (instead of macro cellular, etc) + return null; + } + + public VcnTransportInfo[] newArray(int size) { + return new VcnTransportInfo[size]; + } + }; +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java new file mode 100644 index 0000000000..31561901be --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -0,0 +1,71 @@ +/* + * 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 android.net.vcn; + +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; + +import android.net.wifi.WifiInfo; +import android.os.Parcel; + +import org.junit.Test; + +public class VcnTransportInfoTest { + private static final int SUB_ID = 1; + private static final int NETWORK_ID = 5; + private static final WifiInfo WIFI_INFO = + new WifiInfo.Builder().setNetworkId(NETWORK_ID).build(); + + private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); + private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); + + @Test + public void testGetWifiInfo() { + assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); + + assertNull(CELL_UNDERLYING_INFO.getWifiInfo()); + } + + @Test + public void testGetSubId() { + assertEquals(SUB_ID, CELL_UNDERLYING_INFO.getSubId()); + + assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId()); + } + + @Test + public void testEquals() { + assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO); + assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); + assertNotEquals(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); + } + + @Test + public void testParcelUnparcel() { + verifyParcelingIsNull(CELL_UNDERLYING_INFO); + verifyParcelingIsNull(WIFI_UNDERLYING_INFO); + } + + private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { + Parcel parcel = Parcel.obtain(); + vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); + assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); + } +} From 677039b8e72e4e6aab29b282e4c73f32d9433105 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 15 Jan 2021 23:56:44 +0900 Subject: [PATCH 0028/1057] Remove usage of NetCapability The NetCapability annotation is internal to NetworkCapabilities. IntDef annotations cannot be part of the API as per API guidelines, so the NetCapability annotation cannot be used from outside of the connectivity module, once it is built. Bug: 174436414 Test: m Change-Id: I1d6d87432d1e3af8a20169b18ceffa0c1130a836 --- .../net/vcn/VcnGatewayConnectionConfig.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 039360a69a..d531cdb2a6 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,8 +15,6 @@ */ package android.net.vcn; -import static android.net.NetworkCapabilities.NetCapability; - import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntRange; @@ -233,7 +231,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean hasExposedCapability(@NetCapability int capability) { + public boolean hasExposedCapability(int capability) { checkValidCapability(capability); return mExposedCapabilities.contains(capability); @@ -254,7 +252,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean requiresUnderlyingCapability(@NetCapability int capability) { + public boolean requiresUnderlyingCapability(int capability) { checkValidCapability(capability); return mUnderlyingCapabilities.contains(capability); @@ -341,7 +339,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder addExposedCapability(@NetCapability int exposedCapability) { + public Builder addExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); @@ -357,7 +355,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder removeExposedCapability(@NetCapability int exposedCapability) { + public Builder removeExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -373,7 +371,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder addRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.add(underlyingCapability); @@ -393,7 +391,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder removeRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.remove(underlyingCapability); From 2d692579028df8fee08916436bd833964132dd5d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 15 Dec 2020 15:27:49 -0800 Subject: [PATCH 0029/1057] Define VcnUnderlyingNetworkPolicy. Bug: 175729529 Test: atest FrameworksVcnTests Change-Id: I57c732640d6d21db1f4d68c69ff320918e7891c3 --- .../net/vcn/VcnUnderlyingNetworkPolicy.aidl | 20 ++++ .../net/vcn/VcnUnderlyingNetworkPolicy.java | 110 ++++++++++++++++++ Vcn/tests/unit/Android.bp | 1 + .../vcn/VcnUnderlyingNetworkPolicyTest.java | 51 ++++++++ 4 files changed, 182 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl new file mode 100644 index 0000000000..6cb6ee685a --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl @@ -0,0 +1,20 @@ +/* + * 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.vcn; + +/** @hide */ +parcelable VcnUnderlyingNetworkPolicy; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java new file mode 100644 index 0000000000..dd7c86d87f --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -0,0 +1,110 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network. + * + *

    Transports that are bringing up networks capable of acting as a VCN's underlying network + * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener. + * + * @hide + */ +public final class VcnUnderlyingNetworkPolicy implements Parcelable { + private final boolean mIsTearDownRequested; + private final NetworkCapabilities mMergedNetworkCapabilities; + + /** + * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters. + * + * @hide + */ + public VcnUnderlyingNetworkPolicy( + boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) { + Objects.requireNonNull( + mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull"); + + mIsTearDownRequested = isTearDownRequested; + mMergedNetworkCapabilities = mergedNetworkCapabilities; + } + + /** + * Returns whether this Carrier VCN policy policy indicates that the underlying Network should + * be torn down. + */ + public boolean isTeardownRequested() { + return mIsTearDownRequested; + } + + /** + * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided + * capabilities. + */ + @NonNull + public NetworkCapabilities getMergedNetworkCapabilities() { + return mMergedNetworkCapabilities; + } + + @Override + public int hashCode() { + return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false; + final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o; + + return mIsTearDownRequested == that.mIsTearDownRequested + && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsTearDownRequested); + dest.writeParcelable(mMergedNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { + return new VcnUnderlyingNetworkPolicy( + in.readBoolean(), in.readParcelable(null)); + } + + public VcnUnderlyingNetworkPolicy[] newArray(int size) { + return new VcnUnderlyingNetworkPolicy[size]; + } + }; +} diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 3c08d347b1..c04ddd78e6 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -16,6 +16,7 @@ android_test { "frameworks-base-testutils", "framework-protos", "mockito-target-minus-junit4", + "net-tests-utils", "platform-test-annotations", "services.core", ], diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java new file mode 100644 index 0000000000..3ba0a1f53a --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -0,0 +1,51 @@ +/* + * 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.vcn; + +import static com.android.testutils.ParcelUtils.assertParcelSane; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.net.NetworkCapabilities; + +import org.junit.Test; + +public class VcnUnderlyingNetworkPolicyTest { + private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY = + new VcnUnderlyingNetworkPolicy( + false /* isTearDownRequested */, new NetworkCapabilities()); + private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY = + new VcnUnderlyingNetworkPolicy( + true /* isTearDownRequested */, + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .build()); + + @Test + public void testEquals() { + assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY); + assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY); + + assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY); + } + + @Test + public void testParcelUnparcel() { + assertParcelSane(SAMPLE_NETWORK_POLICY, 2); + } +} From 230f02c272667c99e190a0fbb6a136d04f50dc71 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 15 Dec 2020 15:27:49 -0800 Subject: [PATCH 0030/1057] Define add and remove for VCN policy listeners. Bug: 175729529 Test: atest FrameworksVcnTests Change-Id: I61dd789fe4a4ebd1ca95866494d0e42e97c202cc --- .../net/vcn/IVcnManagementService.aidl | 4 + .../IVcnUnderlyingNetworkPolicyListener.aidl | 22 ++++ .../src/android/net/vcn/VcnManager.java | 107 ++++++++++++++++++ .../android/server/VcnManagementService.java | 17 +++ .../java/android/net/vcn/VcnManagerTest.java | 106 +++++++++++++++++ 5 files changed, 256 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 04b585cdf4..80ac64b87d 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -16,6 +16,7 @@ package android.net.vcn; +import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.os.ParcelUuid; @@ -25,4 +26,7 @@ import android.os.ParcelUuid; interface IVcnManagementService { void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); void clearVcnConfig(in ParcelUuid subscriptionGroup); + + void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); + void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); } diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl new file mode 100644 index 0000000000..f8ae492016 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl @@ -0,0 +1,22 @@ +/* + * 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.vcn; + +/** @hide */ +interface IVcnUnderlyingNetworkPolicyListener { + void onPolicyChanged(); +} \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index b881a33953..2ccdc2633a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -25,7 +25,12 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceSpecificException; +import com.android.internal.annotations.VisibleForTesting; + import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; /** * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. @@ -60,6 +65,11 @@ import java.io.IOException; public final class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + @VisibleForTesting + public static final Map< + VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); + @NonNull private final Context mContext; @NonNull private final IVcnManagementService mService; @@ -136,4 +146,101 @@ public final class VcnManager { throw e.rethrowFromSystemServer(); } } + + // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi + /** + * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components + * can register to receive updates for VCN-underlying Network policies from the System Server. + * + * @hide + */ + public interface VcnUnderlyingNetworkPolicyListener { + /** + * Notifies the implementation that the VCN's underlying Network policy has changed. + * + *

    After receiving this callback, implementations MUST poll VcnManager for the updated + * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy. + */ + void onPolicyChanged(); + } + + /** + * Add a listener for VCN-underlying network policy updates. + * + * @param executor the Executor that will be used for invoking all calls to the specified + * Listener + * @param listener the VcnUnderlyingNetworkPolicyListener to be added + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is + * already registered + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void addVcnUnderlyingNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(executor, "executor must not be null"); + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); + if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { + throw new IllegalArgumentException( + "Attempting to add a listener that is already in use"); + } + + try { + mService.addVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + REGISTERED_POLICY_LISTENERS.remove(listener); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager. + * + *

    If the specified listener is not currently registered, this is a no-op. + * + * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed + * @hide + */ + public void removeVcnUnderlyingNetworkPolicyListener( + @NonNull VcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + REGISTERED_POLICY_LISTENERS.remove(listener); + if (binder == null) { + return; + } + + try { + mService.removeVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System + * Server. + * + * @hide + */ + private static class VcnUnderlyingNetworkPolicyListenerBinder + extends IVcnUnderlyingNetworkPolicyListener.Stub { + @NonNull private final Executor mExecutor; + @NonNull private final VcnUnderlyingNetworkPolicyListener mListener; + + private VcnUnderlyingNetworkPolicyListenerBinder( + Executor executor, VcnUnderlyingNetworkPolicyListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onPolicyChanged() { + mExecutor.execute(() -> mListener.onPolicyChanged()); + } + } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index c191a78aad..2fdc796567 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -26,6 +26,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.vcn.IVcnManagementService; +import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.os.Binder; import android.os.Handler; @@ -495,4 +496,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Collections.unmodifiableMap(mVcns); } } + + /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */ + @Override + public void addVcnUnderlyingNetworkPolicyListener( + IVcnUnderlyingNetworkPolicyListener listener) { + // TODO(b/175739863): implement policy listener registration + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ + @Override + public void removeVcnUnderlyingNetworkPolicyListener( + IVcnUnderlyingNetworkPolicyListener listener) { + // TODO(b/175739863): implement policy listener unregistration + throw new UnsupportedOperationException("Not yet implemented"); + } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java new file mode 100644 index 0000000000..9c6b7194af --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -0,0 +1,106 @@ +/* + * 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.vcn; + +import static androidx.test.InstrumentationRegistry.getContext; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.util.concurrent.Executor; + +public class VcnManagerTest { + private static final Executor INLINE_EXECUTOR = Runnable::run; + + private IVcnManagementService mMockVcnManagementService; + private VcnUnderlyingNetworkPolicyListener mMockPolicyListener; + + private Context mContext; + private VcnManager mVcnManager; + + @Before + public void setUp() { + mMockVcnManagementService = mock(IVcnManagementService.class); + mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class); + + mContext = getContext(); + mVcnManager = new VcnManager(mContext, mMockVcnManagementService); + } + + @Test + public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class); + verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture()); + + assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + + IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue(); + listenerWrapper.onPolicyChanged(); + verify(mMockPolicyListener).onPolicyChanged(); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener); + + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + verify(mMockVcnManagementService) + .addVcnUnderlyingNetworkPolicyListener( + any(IVcnUnderlyingNetworkPolicyListener.class)); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception { + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + verify(mMockVcnManagementService, never()) + .addVcnUnderlyingNetworkPolicyListener( + any(IVcnUnderlyingNetworkPolicyListener.class)); + } + + @Test(expected = NullPointerException.class) + public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener); + } + + @Test(expected = NullPointerException.class) + public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null); + } + + @Test(expected = NullPointerException.class) + public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() { + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null); + } +} From a8ac8ae9ec4aa4768455c02bb58f24d4ebd2c04a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Oct 2020 17:48:40 -0700 Subject: [PATCH 0031/1057] Add base states with exception catching and utility functions Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I07de0b7e333a262ab8c3bbff34fa62d4dac7a00a --- .../server/vcn/VcnGatewayConnection.java | 158 +++++++++++++++--- 1 file changed, 136 insertions(+), 22 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 7024e67a82..4e0c0c5492 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -123,7 +123,7 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; - private static final int TOKEN_ANY = Integer.MIN_VALUE; + private static final int TOKEN_ALL = Integer.MIN_VALUE; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; @@ -139,7 +139,7 @@ public class VcnGatewayConnection extends StateMachine { * *

    In the Connected state, this MAY indicate a mobility even occurred. * - * @param arg1 The "any" token; this event is always applicable. + * @param arg1 The "all" token; this event is always applicable. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. */ private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; @@ -175,7 +175,7 @@ public class VcnGatewayConnection extends StateMachine { *

    Upon receipt of this signal, the state machine will transition from the Retry-timeout * state to the Connecting state. * - * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState. + * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState. */ private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; @@ -318,7 +318,7 @@ public class VcnGatewayConnection extends StateMachine { *

    Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * any pending work items, and move to the Disconnected state. * - * @param arg1 The "any" token; this signal is always honored. + * @param arg1 The "all" token; this signal is always honored. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. */ private static final int EVENT_DISCONNECT_REQUESTED = 7; @@ -504,16 +504,9 @@ public class VcnGatewayConnection extends StateMachine { *

    Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - mUnderlyingNetworkTracker.teardown(); - - // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. - if (mTunnelIface != null) { - mTunnelIface.close(); - } - sendMessage( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); quit(); @@ -521,6 +514,16 @@ public class VcnGatewayConnection extends StateMachine { // is also called asynchronously when a NetworkAgent becomes unwanted } + @Override + protected void onQuitting() { + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. + if (mTunnelIface != null) { + mTunnelIface.close(); + } + + mUnderlyingNetworkTracker.teardown(); + } + private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override public void onSelectedUnderlyingNetworkChanged( @@ -530,26 +533,24 @@ public class VcnGatewayConnection extends StateMachine { if (underlying == null) { sendMessageDelayed( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); - return; - } + } else if (getHandler() != null) { + // Cancel any existing disconnect due to loss of underlying network + // getHandler() can return null if the state machine has already quit. Since this is + // called from other classes, this condition must be verified. - // Cancel any existing disconnect due to loss of underlying network - // getHandler() can return null if the state machine has already quit. Since this is - // called - // from other classes, this condition must be verified. - if (getHandler() != null) { getHandler() .removeEqualMessages( EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } + sendMessage( EVENT_UNDERLYING_NETWORK_CHANGED, - TOKEN_ANY, + TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); } } @@ -594,10 +595,101 @@ public class VcnGatewayConnection extends StateMachine { } private abstract class BaseState extends State { + @Override + public void enter() { + try { + enterState(); + } catch (Exception e) { + Slog.wtf(TAG, "Uncaught exception", e); + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + } + } + protected void enterState() throws Exception {} + /** + * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng + * builds. + */ + @Override + public boolean processMessage(Message msg) { + try { + processStateMsg(msg); + } catch (Exception e) { + Slog.wtf(TAG, "Uncaught exception", e); + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + } + + return HANDLED; + } + protected abstract void processStateMsg(Message msg) throws Exception; + + protected void logUnhandledMessage(Message msg) { + // Log as unexpected all known messages, and log all else as unknown. + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough + case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough + case EVENT_SESSION_LOST: // Fallthrough + case EVENT_SESSION_CLOSED: // Fallthrough + case EVENT_TRANSFORM_CREATED: // Fallthrough + case EVENT_SETUP_COMPLETED: // Fallthrough + case EVENT_DISCONNECT_REQUESTED: // Fallthrough + case EVENT_TEARDOWN_TIMEOUT_EXPIRED: + logUnexpectedEvent(msg.what); + break; + default: + logWtfUnknownEvent(msg.what); + break; + } + } + + protected void teardownNetwork() { + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); + mNetworkAgent = null; + } + } + + protected void teardownIke() { + if (mIkeSession != null) { + mIkeSession.close(); + } + } + + protected void handleDisconnectRequested(String msg) { + Slog.v(TAG, "Tearing down. Cause: " + msg); + teardownNetwork(); + teardownIke(); + + if (mIkeSession == null) { + // Already disconnected, go straight to DisconnectedState + transitionTo(mDisconnectedState); + } else { + // Still need to wait for full closure + transitionTo(mDisconnectingState); + } + } + + protected void logUnexpectedEvent(int what) { + Slog.d(TAG, String.format( + "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); + } + + protected void logWtfUnknownEvent(int what) { + Slog.wtf(TAG, String.format( + "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); + } } + /** * State representing the a disconnected VCN tunnel. * @@ -608,7 +700,29 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} } - private abstract class ActiveBaseState extends BaseState {} + private abstract class ActiveBaseState extends BaseState { + /** + * Handles all incoming messages, discarding messages for previous networks. + * + *

    States that handle mobility events may need to override this method to receive + * messages for all underlying networks. + */ + @Override + public boolean processMessage(Message msg) { + final int token = msg.arg1; + // Only process if a valid token is presented. + if (isValidToken(token)) { + return super.processMessage(msg); + } + + Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); + return HANDLED; + } + + protected boolean isValidToken(int token) { + return (token == TOKEN_ALL || token == mCurrentToken); + } + } /** * Transitive state representing a VCN that is tearing down an IKE session. From eb7badf1c995836329ff7c6dd70742c3dec87ec1 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 16 Dec 2020 11:43:58 -0800 Subject: [PATCH 0032/1057] Implement Policy Listener add/remove in VcnService. This CL updates VcnManagementService to implement VcnUnderlyingNetworkPolicyListener add and remove operations. It also adds functionality to remove any listeners if the registering app dies without unregistering. Bug: 175739863 Test: atest FrameworksVcnTests Change-Id: I9db2729d404f232b84577d2d90909b9152d53b5a --- .../android/server/VcnManagementService.java | 61 +++++++++++++++++-- .../server/VcnManagementServiceTest.java | 49 +++++++++++++++ 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 2fdc796567..76db0192cb 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -31,16 +31,19 @@ import android.net.vcn.VcnConfig; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -155,6 +158,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper; + @GuardedBy("mLock") + @NonNull + private final Map mRegisteredPolicyListeners = + new ArrayMap<>(); + @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { mContext = requireNonNull(context, "Missing context"); @@ -497,19 +505,60 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + /** Binder death recipient used to remove a registered policy listener. */ + private class PolicyListenerBinderDeath implements Binder.DeathRecipient { + @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener; + + PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) { + mListener = listener; + } + + @Override + public void binderDied() { + Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener"); + removeVcnUnderlyingNetworkPolicyListener(mListener); + } + } + /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */ + @GuardedBy("mLock") @Override public void addVcnUnderlyingNetworkPolicyListener( - IVcnUnderlyingNetworkPolicyListener listener) { - // TODO(b/175739863): implement policy listener registration - throw new UnsupportedOperationException("Not yet implemented"); + @NonNull IVcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(listener, "listener was null"); + + mContext.enforceCallingPermission( + android.Manifest.permission.NETWORK_FACTORY, + "Must have permission NETWORK_FACTORY to register a policy listener"); + + PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); + + synchronized (mLock) { + mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath); + + try { + listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */); + } catch (RemoteException e) { + // Remote binder already died - cleanup registered Listener + listenerBinderDeath.binderDied(); + } + } } /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ + @GuardedBy("mLock") @Override public void removeVcnUnderlyingNetworkPolicyListener( - IVcnUnderlyingNetworkPolicyListener listener) { - // TODO(b/175739863): implement policy listener unregistration - throw new UnsupportedOperationException("Not yet implemented"); + @NonNull IVcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(listener, "listener was null"); + + synchronized (mLock) { + PolicyListenerBinderDeath listenerBinderDeath = + mRegisteredPolicyListeners.remove(listener.asBinder()); + + if (listenerBinderDeath != null) { + listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */); + } + } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 696110f018..29cfdb6fd5 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,10 +23,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -35,8 +40,10 @@ import static org.mockito.Mockito.verify; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; +import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.Process; @@ -126,6 +133,10 @@ public class VcnManagementServiceTest { private final VcnManagementService mVcnMgmtSvc; + private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener = + mock(IVcnUnderlyingNetworkPolicyListener.class); + private final IBinder mMockIBinder = mock(IBinder.class); + public VcnManagementServiceTest() throws Exception { setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); @@ -169,6 +180,8 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); + // Make sure the profiles are loaded. mTestLooper.dispatchAll(); } @@ -438,4 +451,40 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); verify(vcnInstance).teardownAsynchronously(); } + + @Test + public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception { + doNothing() + .when(mMockContext) + .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + verify(mMockIBinder).linkToDeath(any(), anyInt()); + } + + @Test(expected = SecurityException.class) + public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() { + doThrow(new SecurityException()) + .when(mMockContext) + .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListener() { + // verify listener added + doNothing() + .when(mMockContext) + .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() { + mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } } From c0f9d053a795d5551c27b7dc6f48e2b71f5ea8b9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Oct 2020 17:49:42 -0700 Subject: [PATCH 0033/1057] Implement Disconnected state This change implements the signal handling for the Disconnected state. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I4853b0801b82fddc4ef9e9c6e6a659f9b81e2ac3 --- .../server/vcn/UnderlyingNetworkTracker.java | 6 +- .../server/vcn/VcnGatewayConnection.java | 89 +++++++++++++-- .../server/VcnManagementServiceTest.java | 19 ++-- ...atewayConnectionDisconnectedStateTest.java | 84 ++++++++++++++ .../vcn/VcnGatewayConnectionTestBase.java | 105 ++++++++++++++++++ .../com/android/server/vcn/VcnTestUtils.java | 44 ++++++++ 6 files changed, 328 insertions(+), 19 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnTestUtils.java diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index e1feb5aab8..6427ae2dc1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -24,6 +24,9 @@ import android.net.NetworkCapabilities; import android.os.Handler; import android.os.ParcelUuid; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + import java.util.Objects; /** @@ -72,7 +75,8 @@ public class UnderlyingNetworkTracker extends Handler { @NonNull public final LinkProperties linkProperties; public final boolean blocked; - private UnderlyingNetworkRecord( + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 4e0c0c5492..93cf470c3b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -360,11 +360,25 @@ public class VcnGatewayConnection extends StateMachine { */ private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8; - @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState(); - @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState(); - @NonNull private final ConnectingState mConnectingState = new ConnectingState(); - @NonNull private final ConnectedState mConnectedState = new ConnectedState(); - @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final DisconnectedState mDisconnectedState = new DisconnectedState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final DisconnectingState mDisconnectingState = new DisconnectingState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final ConnectingState mConnectingState = new ConnectingState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final ConnectedState mConnectedState = new ConnectedState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @@ -455,7 +469,8 @@ public class VcnGatewayConnection extends StateMachine { this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies()); } - private VcnGatewayConnection( + @VisibleForTesting(visibility = Visibility.PRIVATE) + VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnGatewayConnectionConfig connectionConfig, @@ -508,7 +523,6 @@ public class VcnGatewayConnection extends StateMachine { EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); - quit(); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -667,6 +681,8 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(String msg) { Slog.v(TAG, "Tearing down. Cause: " + msg); + mIsRunning = false; + teardownNetwork(); teardownIke(); @@ -697,7 +713,37 @@ public class VcnGatewayConnection extends StateMachine { */ private class DisconnectedState extends BaseState { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() { + if (!mIsRunning) { + quitNow(); // Ignore all queued events; cleanup is complete. + } + + if (mIkeSession != null || mNetworkAgent != null) { + Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); + } + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: + // First network found; start tunnel + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + if (mUnderlying != null) { + transitionTo(mConnectingState); + } + break; + case EVENT_DISCONNECT_REQUESTED: + mIsRunning = false; + + quitNow(); + break; + default: + logUnhandledMessage(msg); + break; + } + } } private abstract class ActiveBaseState extends BaseState { @@ -893,7 +939,32 @@ public class VcnGatewayConnection extends StateMachine { } } - /** External dependencies used by VcnGatewayConnection, for injection in tests. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() { + return mUnderlyingNetworkTrackerCallback; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkRecord getUnderlyingNetwork() { + return mUnderlying; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) { + mUnderlying = record; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + boolean isRunning() { + return mIsRunning; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setIsRunning(boolean isRunning) { + mIsRunning = isRunning; + } + + /** External dependencies used by VcnGatewayConnection, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { /** Builds a new UnderlyingNetworkTracker. */ diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 696110f018..131d9c3aed 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -18,6 +18,7 @@ package com.android.server; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; +import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -127,11 +128,16 @@ public class VcnManagementServiceTest { private final VcnManagementService mVcnMgmtSvc; public VcnManagementServiceTest() throws Exception { - setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); - setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); setupSystemService( - mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class); - setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); + mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService( + mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mMockContext, + mSubMgr, + Context.TELEPHONY_SUBSCRIPTION_SERVICE, + SubscriptionManager.class); + setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName(); @@ -173,11 +179,6 @@ public class VcnManagementServiceTest { mTestLooper.dispatchAll(); } - private void setupSystemService(Object service, String name, Class serviceClass) { - doReturn(name).when(mMockContext).getSystemServiceName(serviceClass); - doReturn(service).when(mMockContext).getSystemService(name); - } - private void setupMockedCarrierPrivilege(boolean isPrivileged) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java new file mode 100644 index 0000000000..4ecd215031 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -0,0 +1,84 @@ +/* + * 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.vcn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for VcnGatewayConnection.DisconnectedState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase { + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState); + mTestLooper.dispatchAll(); + } + + @Test + public void testEnterWhileNotRunningTriggersQuit() throws Exception { + final VcnGatewayConnection vgc = + new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + + vgc.setIsRunning(false); + vgc.transitionTo(vgc.mDisconnectedState); + mTestLooper.dispatchAll(); + + assertNull(vgc.getCurrentState()); + } + + @Test + public void testNetworkChangesTriggerStateTransitions() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testNullNetworkDoesNotTriggerStateTransition() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getCurrentState()); + verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java new file mode 100644 index 0000000000..1725dd9831 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -0,0 +1,105 @@ +/* + * 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.vcn; + +import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.IpSecManager; +import android.net.IpSecTunnelInterfaceResponse; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.os.ParcelUuid; +import android.os.test.TestLooper; + +import com.android.server.IpSecService; + +import org.junit.Before; + +import java.util.UUID; + +public class VcnGatewayConnectionTestBase { + protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1; + protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = + new UnderlyingNetworkRecord( + new Network(0), + new NetworkCapabilities(), + new LinkProperties(), + false /* blocked */); + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = + new UnderlyingNetworkRecord( + new Network(1), + new NetworkCapabilities(), + new LinkProperties(), + false /* blocked */); + + @NonNull protected final Context mContext; + @NonNull protected final TestLooper mTestLooper; + @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; + @NonNull protected final VcnContext mVcnContext; + @NonNull protected final VcnGatewayConnectionConfig mConfig; + @NonNull protected final VcnGatewayConnection.Dependencies mDeps; + @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + + @NonNull protected final IpSecService mIpSecSvc; + + protected VcnGatewayConnection mGatewayConnection; + + public VcnGatewayConnectionTestBase() { + mContext = mock(Context.class); + mTestLooper = new TestLooper(); + mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mVcnContext = mock(VcnContext.class); + mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); + mDeps = mock(VcnGatewayConnection.Dependencies.class); + mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); + + mIpSecSvc = mock(IpSecService.class); + setupIpSecManager(mContext, mIpSecSvc); + + doReturn(mContext).when(mVcnContext).getContext(); + doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); + doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + + doReturn(mUnderlyingNetworkTracker) + .when(mDeps) + .newUnderlyingNetworkTracker(any(), any(), any()); + } + + @Before + public void setUp() throws Exception { + IpSecTunnelInterfaceResponse resp = + new IpSecTunnelInterfaceResponse( + IpSecManager.Status.OK, + TEST_IPSEC_TUNNEL_RESOURCE_ID, + TEST_IPSEC_TUNNEL_IFACE); + doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); + + mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTestUtils.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTestUtils.java new file mode 100644 index 0000000000..2b1080650d --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTestUtils.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.server.vcn; + +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.net.IpSecManager; + +import com.android.server.IpSecService; + +public class VcnTestUtils { + /** Mock system services by directly mocking the *Manager interface. */ + public static void setupSystemService( + Context mockContext, Object service, String name, Class serviceClass) { + doReturn(name).when(mockContext).getSystemServiceName(serviceClass); + doReturn(service).when(mockContext).getSystemService(name); + } + + /** Mock IpSecService by mocking the underlying service binder. */ + public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) { + doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class); + + final IpSecManager ipSecMgr = new IpSecManager(mockContext, service); + doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE); + + // Return to ensure this doesn't get reaped. + return ipSecMgr; + } +} From 350bc97eb83a07daed1905ca724cf773067c1cb3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 25 Jan 2021 18:27:02 -0800 Subject: [PATCH 0034/1057] Remove usage of NetworkInfo Remove usages of deprecated APIs Bug: 8675309 Test: atest FrameworksVcnTests Change-Id: Iaaef109d00c111da2396c3eec946cfc5035f415e --- .../server/vcn/VcnGatewayConnection.java | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 93cf470c3b..0fa97a26e6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -24,7 +24,6 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; @@ -36,8 +35,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -54,7 +51,6 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; -import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -668,7 +664,7 @@ public class VcnGatewayConnection extends StateMachine { protected void teardownNetwork() { if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); + mNetworkAgent.unregister(); mNetworkAgent = null; } } @@ -815,20 +811,6 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} } - // TODO: Remove this when migrating to new NetworkAgent API - private static NetworkInfo buildNetworkInfo(boolean isConnected) { - NetworkInfo info = - new NetworkInfo( - ConnectivityManager.TYPE_MOBILE, - TelephonyManager.NETWORK_TYPE_UNKNOWN, - "MOBILE", - "VCN"); - info.setDetailedState( - isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null); - - return info; - } - @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { From da60ff3a384e112058b574a5af55d5f3609cf428 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 11 Jan 2021 15:50:30 -0800 Subject: [PATCH 0035/1057] Implement DisconnectingState This change implements the Disconnecting state, which provides facility to attempt to gracefully close IKE sessions, and kill it after a few seconds. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I0d179085726b8125f2021679def75824cf71bd08 --- .../server/vcn/VcnGatewayConnection.java | 166 ++++++++++++++++-- ...tewayConnectionDisconnectingStateTest.java | 71 ++++++++ .../vcn/VcnGatewayConnectionTestBase.java | 15 ++ 3 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 0fa97a26e6..8805fa2f4d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -122,7 +122,9 @@ public class VcnGatewayConnection extends StateMachine { private static final int TOKEN_ALL = Integer.MIN_VALUE; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; - private static final int TEARDOWN_TIMEOUT_SECONDS = 5; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int TEARDOWN_TIMEOUT_SECONDS = 5; private interface EventInfo {} @@ -412,13 +414,6 @@ public class VcnGatewayConnection extends StateMachine { */ private int mCurrentToken = -1; - /** - * The next usable token. - * - *

    A new token MUST be used for all new IKE sessions. - */ - private int mNextToken = 0; - /** * The number of unsuccessful attempts since the last successful connection. * @@ -440,7 +435,7 @@ public class VcnGatewayConnection extends StateMachine { *

    Set in Connecting or Migrating States, always @NonNull in Connecting, Connected, and * Migrating states, null otherwise. */ - private IkeSession mIkeSession; + private VcnIkeSession mIkeSession; /** * The last known child configuration. @@ -774,7 +769,70 @@ public class VcnGatewayConnection extends StateMachine { */ private class DisconnectingState extends ActiveBaseState { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() throws Exception { + if (mIkeSession == null) { + Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state."); + sendMessage(EVENT_SESSION_CLOSED, mCurrentToken); + return; + } + + // If underlying network has already been lost, save some time and just kill the session + if (mUnderlying == null) { + // Will trigger a EVENT_SESSION_CLOSED as IkeSession shuts down. + mIkeSession.kill(); + return; + } + + sendMessageDelayed( + EVENT_TEARDOWN_TIMEOUT_EXPIRED, + mCurrentToken, + TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS)); + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + // If we received a new underlying network, continue. + if (mUnderlying != null) { + break; + } + + // Fallthrough; no network exists to send IKE close session requests. + case EVENT_TEARDOWN_TIMEOUT_EXPIRED: + // Grace period ended. Kill session, triggering EVENT_SESSION_CLOSED + mIkeSession.kill(); + + break; + case EVENT_DISCONNECT_REQUESTED: + teardownNetwork(); + + String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; + if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { + // Will trigger EVENT_SESSION_CLOSED immediately. + mIkeSession.kill(); + break; + } + + // Otherwise we are already in the process of shutting down. + break; + case EVENT_SESSION_CLOSED: + mIkeSession = null; + + if (mIsRunning && mUnderlying != null) { + transitionTo(mRetryTimeoutState); + } else { + teardownNetwork(); + transitionTo(mDisconnectedState); + } + break; + default: + logUnhandledMessage(msg); + break; + } + } } /** @@ -946,6 +1004,38 @@ public class VcnGatewayConnection extends StateMachine { mIsRunning = isRunning; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + VcnIkeSession getIkeSession() { + return mIkeSession; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setIkeSession(@Nullable VcnIkeSession session) { + mIkeSession = session; + } + + private IkeSessionParams buildIkeParams() { + // TODO: Implement this with ConnectingState + return null; + } + + private ChildSessionParams buildChildParams() { + // TODO: Implement this with ConnectingState + return null; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + VcnIkeSession buildIkeSession() { + final int token = ++mCurrentToken; + + return mDeps.newIkeSession( + mVcnContext, + buildIkeParams(), + buildChildParams(), + new IkeSessionCallbackImpl(token), + new ChildSessionCallbackImpl(token)); + } + /** External dependencies used by VcnGatewayConnection, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -958,19 +1048,67 @@ public class VcnGatewayConnection extends StateMachine { } /** Builds a new IkeSession. */ - public IkeSession newIkeSession( + public VcnIkeSession newIkeSession( VcnContext vcnContext, IkeSessionParams ikeSessionParams, ChildSessionParams childSessionParams, IkeSessionCallback ikeSessionCallback, ChildSessionCallback childSessionCallback) { - return new IkeSession( - vcnContext.getContext(), + return new VcnIkeSession( + vcnContext, ikeSessionParams, childSessionParams, - new HandlerExecutor(new Handler(vcnContext.getLooper())), ikeSessionCallback, childSessionCallback); } } + + /** Proxy implementation of IKE session, used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnIkeSession { + private final IkeSession mImpl; + + public VcnIkeSession( + VcnContext vcnContext, + IkeSessionParams ikeSessionParams, + ChildSessionParams childSessionParams, + IkeSessionCallback ikeSessionCallback, + ChildSessionCallback childSessionCallback) { + mImpl = + new IkeSession( + vcnContext.getContext(), + ikeSessionParams, + childSessionParams, + new HandlerExecutor(new Handler(vcnContext.getLooper())), + ikeSessionCallback, + childSessionCallback); + } + + /** Creates a new IKE Child session. */ + public void openChildSession( + @NonNull ChildSessionParams childSessionParams, + @NonNull ChildSessionCallback childSessionCallback) { + mImpl.openChildSession(childSessionParams, childSessionCallback); + } + + /** Closes an IKE session as identified by the ChildSessionCallback. */ + public void closeChildSession(@NonNull ChildSessionCallback childSessionCallback) { + mImpl.closeChildSession(childSessionCallback); + } + + /** Gracefully closes this IKE Session, waiting for remote acknowledgement. */ + public void close() { + mImpl.close(); + } + + /** Forcibly kills this IKE Session, without waiting for a closure confirmation. */ + public void kill() { + mImpl.kill(); + } + + /** Sets the underlying network used by the IkeSession. */ + public void setNetwork(@NonNull Network network) { + mImpl.setNetwork(network); + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java new file mode 100644 index 0000000000..d0fec55a68 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -0,0 +1,71 @@ +/* + * 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.vcn; + +import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +/** Tests for VcnGatewayConnection.DisconnectedState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase { + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession()); + + mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState); + mTestLooper.dispatchAll(); + } + + @Test + public void testIkeSessionClosed() throws Exception { + getIkeSessionCallback().onClosed(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testTimeoutExpired() throws Exception { + mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS)); + mTestLooper.dispatchAll(); + + verify(mMockIkeSession).kill(); + } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + // Should do nothing; already tearing down. + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 1725dd9831..346785907f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -17,11 +17,13 @@ package com.android.server.vcn; import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.Context; @@ -30,6 +32,7 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.ipsec.ike.IkeSessionCallback; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; @@ -38,6 +41,7 @@ import android.os.test.TestLooper; import com.android.server.IpSecService; import org.junit.Before; +import org.mockito.ArgumentCaptor; import java.util.UUID; @@ -68,6 +72,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final IpSecService mIpSecSvc; + protected VcnIkeSession mMockIkeSession; protected VcnGatewayConnection mGatewayConnection; public VcnGatewayConnectionTestBase() { @@ -100,6 +105,16 @@ public class VcnGatewayConnectionTestBase { TEST_IPSEC_TUNNEL_IFACE); doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); + mMockIkeSession = mock(VcnIkeSession.class); + doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any()); + mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); } + + protected IkeSessionCallback getIkeSessionCallback() { + ArgumentCaptor captor = + ArgumentCaptor.forClass(IkeSessionCallback.class); + verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any()); + return captor.getValue(); + } } From 92ed6cb3f350abdef53fb5b0f81f4778ada92fca Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 19 Jan 2021 18:58:47 -0800 Subject: [PATCH 0036/1057] Prep VCN files for exposing APIs Add @hide to methods to clearly show what is being exposed and cleanup some visibilty/final modifiers. Bug: 168833866 Test: atest FrameworksVcnTests Test: atest android.net.vcn Change-Id: I8e03133053b59fd5b8df640e4b22761f572f9548 --- .../src/android/net/vcn/VcnConfig.java | 18 ++- .../net/vcn/VcnGatewayConnectionConfig.java | 146 ++++++++++++++---- .../src/android/net/vcn/VcnManager.java | 1 + .../vcn/VcnGatewayConnectionConfigTest.java | 20 ++- 4 files changed, 144 insertions(+), 41 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index ede8faaaf2..5eb4ba6a2f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -96,7 +96,11 @@ public final class VcnConfig implements Parcelable { return mPackageName; } - /** Retrieves the set of configured tunnels. */ + /** + * Retrieves the set of configured tunnels. + * + * @hide + */ @NonNull public Set getGatewayConnectionConfigs() { return Collections.unmodifiableSet(mGatewayConnectionConfigs); @@ -146,7 +150,7 @@ public final class VcnConfig implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeParcelable(toPersistableBundle(), flags); } @@ -164,8 +168,12 @@ public final class VcnConfig implements Parcelable { } }; - /** This class is used to incrementally build {@link VcnConfig} objects. */ - public static class Builder { + /** + * This class is used to incrementally build {@link VcnConfig} objects. + * + * @hide + */ + public static final class Builder { @NonNull private final String mPackageName; @NonNull @@ -182,6 +190,7 @@ public final class VcnConfig implements Parcelable { * * @param gatewayConnectionConfig the configuration for an individual gateway connection * @return this {@link Builder} instance, for chaining + * @hide */ @NonNull public Builder addGatewayConnectionConfig( @@ -196,6 +205,7 @@ public final class VcnConfig implements Parcelable { * Builds and validates the VcnConfig. * * @return an immutable VcnConfig instance + * @hide */ @NonNull public VcnConfig build() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index d531cdb2a6..cead2f1caa 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -17,6 +17,7 @@ package android.net.vcn; import static com.android.internal.annotations.VisibleForTesting.Visibility; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -25,14 +26,19 @@ import android.os.PersistableBundle; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.TimeUnit; /** @@ -97,6 +103,26 @@ public final class VcnGatewayConnectionConfig { ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"NET_CAPABILITY_"}, + value = { + NetworkCapabilities.NET_CAPABILITY_MMS, + NetworkCapabilities.NET_CAPABILITY_SUPL, + NetworkCapabilities.NET_CAPABILITY_DUN, + NetworkCapabilities.NET_CAPABILITY_FOTA, + NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_CBS, + NetworkCapabilities.NET_CAPABILITY_IA, + NetworkCapabilities.NET_CAPABILITY_RCS, + NetworkCapabilities.NET_CAPABILITY_XCAP, + NetworkCapabilities.NET_CAPABILITY_EIMS, + NetworkCapabilities.NET_CAPABILITY_INTERNET, + NetworkCapabilities.NET_CAPABILITY_MCX, + }) + public @interface VcnSupportedCapability {} + private static final int DEFAULT_MAX_MTU = 1500; /** @@ -128,10 +154,10 @@ public final class VcnGatewayConnectionConfig { }; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; - @NonNull private final Set mExposedCapabilities; + @NonNull private final SortedSet mExposedCapabilities; private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; - @NonNull private final Set mUnderlyingCapabilities; + @NonNull private final SortedSet mUnderlyingCapabilities; // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig @@ -141,14 +167,14 @@ public final class VcnGatewayConnectionConfig { private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; @NonNull private final long[] mRetryIntervalsMs; - @VisibleForTesting(visibility = Visibility.PRIVATE) - public VcnGatewayConnectionConfig( + /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ + private VcnGatewayConnectionConfig( @NonNull Set exposedCapabilities, @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { - mExposedCapabilities = exposedCapabilities; - mUnderlyingCapabilities = underlyingCapabilities; + mExposedCapabilities = new TreeSet(exposedCapabilities); + mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; @@ -163,9 +189,9 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle underlyingCapsBundle = in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); - mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -219,52 +245,93 @@ public final class VcnGatewayConnectionConfig { /** * Returns all exposed capabilities. * + *

    The returned integer-value capabilities will not contain duplicates, and will be sorted in + * ascending numerical order. + * + * @see Builder#addExposedCapability(int) + * @see Builder#clearExposedCapability(int) * @hide */ @NonNull + public int[] getExposedCapabilities() { + // Sorted set guarantees ordering + return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities)); + } + + /** + * Returns all exposed capabilities. + * + *

    Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getExposedCapabilities() instead + * @hide + */ + @Deprecated + @NonNull public Set getAllExposedCapabilities() { return Collections.unmodifiableSet(mExposedCapabilities); } /** - * Checks if this config is configured to support/expose a specific capability. + * Returns all capabilities required of underlying networks. * - * @param capability the capability to check for + *

    The returned integer-value capabilities will be sorted in ascending numerical order. + * + * @see Builder#addRequiredUnderlyingCapability(int) + * @see Builder#clearRequiredUnderlyingCapability(int) + * @hide */ - public boolean hasExposedCapability(int capability) { - checkValidCapability(capability); - - return mExposedCapabilities.contains(capability); + @NonNull + public int[] getRequiredUnderlyingCapabilities() { + // Sorted set guarantees ordering + return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities)); } /** * Returns all capabilities required of underlying networks. * + *

    Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getRequiredUnderlyingCapabilities() instead * @hide */ + @Deprecated @NonNull public Set getAllUnderlyingCapabilities() { return Collections.unmodifiableSet(mUnderlyingCapabilities); } /** - * Checks if this config requires an underlying network to have the specified capability. + * Retrieves the configured retry intervals. * - * @param capability the capability to check for + * @see Builder#setRetryInterval(long[]) + * @hide */ - public boolean requiresUnderlyingCapability(int capability) { - checkValidCapability(capability); - - return mUnderlyingCapabilities.contains(capability); - } - - /** Retrieves the configured retry intervals. */ @NonNull - public long[] getRetryIntervalsMs() { + public long[] getRetryInterval() { return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } - /** Retrieves the maximum MTU allowed for this Gateway Connection. */ + /** + * Retrieves the configured retry intervals. + * + *

    Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getRequiredUnderlyingCapabilities() instead + * @hide + */ + @Deprecated + @NonNull + public long[] getRetryIntervalsMs() { + return getRetryInterval(); + } + + /** + * Retrieves the maximum MTU allowed for this Gateway Connection. + * + * @see Builder.setMaxMtu(int) + * @hide + */ @IntRange(from = MIN_MTU_V6) public int getMaxMtu() { return mMaxMtu; @@ -319,8 +386,12 @@ public final class VcnGatewayConnectionConfig { && mMaxMtu == rhs.mMaxMtu; } - /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ - public static class Builder { + /** + * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. + * + * @hide + */ + public static final class Builder { @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -338,8 +409,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection + * @hide */ - public Builder addExposedCapability(int exposedCapability) { + @NonNull + public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); @@ -354,8 +427,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection + * @hide */ - public Builder removeExposedCapability(int exposedCapability) { + @NonNull + public Builder clearExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -370,8 +445,11 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ - public Builder addRequiredUnderlyingCapability(int underlyingCapability) { + @NonNull + public Builder addRequiredUnderlyingCapability( + @VcnSupportedCapability int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.add(underlyingCapability); @@ -390,8 +468,11 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ - public Builder removeRequiredUnderlyingCapability(int underlyingCapability) { + @NonNull + public Builder clearRequiredUnderlyingCapability( + @VcnSupportedCapability int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.remove(underlyingCapability); @@ -420,6 +501,7 @@ public final class VcnGatewayConnectionConfig { * 15m]} * @return this {@link Builder} instance, for chaining * @see VcnManager for additional discussion on fail-safe mode + * @hide */ @NonNull public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { @@ -441,6 +523,7 @@ public final class VcnGatewayConnectionConfig { * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than * the IPv6 minimum MTU of 1280. Defaults to 1500. * @return this {@link Builder} instance, for chaining + * @hide */ @NonNull public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { @@ -455,6 +538,7 @@ public final class VcnGatewayConnectionConfig { * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance + * @hide */ @NonNull public VcnGatewayConnectionConfig build() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 2ccdc2633a..2d0a6d74cb 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -65,6 +65,7 @@ import java.util.concurrent.Executor; public final class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + /** @hide */ @VisibleForTesting public static final Map< VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index dfd0c8a751..86a15912b6 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -28,6 +28,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -39,6 +40,12 @@ public class VcnGatewayConnectionConfigTest { NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS }; public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + + static { + Arrays.sort(EXPOSED_CAPS); + Arrays.sort(UNDERLYING_CAPS); + } + public static final long[] RETRY_INTERVALS_MS = new long[] { TimeUnit.SECONDS.toMillis(5), @@ -124,12 +131,13 @@ public class VcnGatewayConnectionConfigTest { public void testBuilderAndGetters() { final VcnGatewayConnectionConfig config = buildTestConfig(); - for (int cap : EXPOSED_CAPS) { - config.hasExposedCapability(cap); - } - for (int cap : UNDERLYING_CAPS) { - config.requiresUnderlyingCapability(cap); - } + int[] exposedCaps = config.getExposedCapabilities(); + Arrays.sort(exposedCaps); + assertArrayEquals(EXPOSED_CAPS, exposedCaps); + + int[] underlyingCaps = config.getRequiredUnderlyingCapabilities(); + Arrays.sort(underlyingCaps); + assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); assertEquals(MAX_MTU, config.getMaxMtu()); From 8fa7f56d97faa92de73e3187a4001b898929498d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Oct 2020 17:50:53 -0700 Subject: [PATCH 0037/1057] Implement ConnectingState This change implements the Connecting state, where the gateway connection will be established. In the event of a network switch during connection, the existing connection attempt will be aborted and restarted on the new network in an attempt to avoid the case where the old network is completely lost (eg wifi to cell switch), and IKE stalls for the entire retry period. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: Id1c6337e8ba4cc1b97c6c20977153c230bd07723 --- .../server/vcn/VcnGatewayConnection.java | 113 ++++++++++++++++-- ...nGatewayConnectionConnectingStateTest.java | 105 ++++++++++++++++ .../vcn/VcnGatewayConnectionTestBase.java | 8 ++ 3 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8805fa2f4d..703bfab6d8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -638,6 +638,22 @@ public class VcnGatewayConnection extends StateMachine { protected abstract void processStateMsg(Message msg) throws Exception; + @Override + public void exit() { + try { + exitState(); + } catch (Exception e) { + Slog.wtf(TAG, "Uncaught exception", e); + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + } + } + + protected void exitState() throws Exception {} + protected void logUnhandledMessage(Message msg) { // Log as unexpected all known messages, and log all else as unknown. switch (msg.what) { @@ -664,18 +680,11 @@ public class VcnGatewayConnection extends StateMachine { } } - protected void teardownIke() { - if (mIkeSession != null) { - mIkeSession.close(); - } - } - protected void handleDisconnectRequested(String msg) { Slog.v(TAG, "Tearing down. Cause: " + msg); mIsRunning = false; teardownNetwork(); - teardownIke(); if (mIkeSession == null) { // Already disconnected, go straight to DisconnectedState @@ -768,6 +777,20 @@ public class VcnGatewayConnection extends StateMachine { * does not complete teardown in a timely fashion, it will be killed (forcibly closed). */ private class DisconnectingState extends ActiveBaseState { + /** + * Whether to skip the RetryTimeoutState and go straight to the ConnectingState. + * + *

    This is used when an underlying network change triggered a restart on a new network. + * + *

    Reset (to false) upon exit of the DisconnectingState. + */ + private boolean mSkipRetryTimeout = false; + + // TODO(b/178441390): Remove this in favor of resetting retry timers on UND_NET change. + public void setSkipRetryTimeout(boolean shouldSkip) { + mSkipRetryTimeout = shouldSkip; + } + @Override protected void enterState() throws Exception { if (mIkeSession == null) { @@ -783,6 +806,7 @@ public class VcnGatewayConnection extends StateMachine { return; } + mIkeSession.close(); sendMessageDelayed( EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken, @@ -822,7 +846,7 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = null; if (mIsRunning && mUnderlying != null) { - transitionTo(mRetryTimeoutState); + transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); } else { teardownNetwork(); transitionTo(mDisconnectedState); @@ -833,6 +857,11 @@ public class VcnGatewayConnection extends StateMachine { break; } } + + @Override + protected void exitState() throws Exception { + mSkipRetryTimeout = false; + } } /** @@ -843,7 +872,69 @@ public class VcnGatewayConnection extends StateMachine { */ private class ConnectingState extends ActiveBaseState { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() { + if (mIkeSession != null) { + Slog.wtf(TAG, "ConnectingState entered with active session"); + + // Attempt to recover. + mIkeSession.kill(); + mIkeSession = null; + } + + mIkeSession = buildIkeSession(); + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: + final UnderlyingNetworkRecord oldUnderlying = mUnderlying; + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + if (oldUnderlying == null) { + // This should never happen, but if it does, there's likely a nasty bug. + Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?"); + } + + // If new underlying is null, all underlying networks have been lost; disconnect + if (mUnderlying == null) { + transitionTo(mDisconnectingState); + break; + } + + if (oldUnderlying != null + && mUnderlying.network.equals(oldUnderlying.network)) { + break; // Only network properties have changed; continue connecting. + } + // Else, retry on the new network. + + // Immediately come back to the ConnectingState (skip RetryTimeout, since this + // isn't a failure) + mDisconnectingState.setSkipRetryTimeout(true); + + // fallthrough - disconnect, and retry on new network. + case EVENT_SESSION_LOST: + transitionTo(mDisconnectingState); + break; + case EVENT_SESSION_CLOSED: + deferMessage(msg); + + transitionTo(mDisconnectingState); + break; + case EVENT_SETUP_COMPLETED: // fallthrough + case EVENT_TRANSFORM_CREATED: + // Child setup complete; move to ConnectedState for NetworkAgent registration + deferMessage(msg); + transitionTo(mConnectedState); + break; + case EVENT_DISCONNECT_REQUESTED: + handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + break; + default: + logUnhandledMessage(msg); + break; + } + } } private abstract class ConnectedStateBase extends ActiveBaseState {} @@ -1015,12 +1106,12 @@ public class VcnGatewayConnection extends StateMachine { } private IkeSessionParams buildIkeParams() { - // TODO: Implement this with ConnectingState + // TODO: Implement this once IkeSessionParams is persisted return null; } private ChildSessionParams buildChildParams() { - // TODO: Implement this with ConnectingState + // TODO: Implement this once IkeSessionParams is persisted return null; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java new file mode 100644 index 0000000000..d936183e5a --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -0,0 +1,105 @@ +/* + * 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.vcn; + +import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for VcnGatewayConnection.ConnectingState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase { + private VcnIkeSession mIkeSession; + + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); + mGatewayConnection.transitionTo(mGatewayConnection.mConnectingState); + mTestLooper.dispatchAll(); + + mIkeSession = mGatewayConnection.getIkeSession(); + } + + @Test + public void testEnterStateCreatesNewIkeSession() throws Exception { + verify(mDeps).newIkeSession(any(), any(), any(), any(), any()); + } + + @Test + public void testNullNetworkTriggersDisconnect() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).kill(); + } + + @Test + public void testNewNetworkTriggersReconnect() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + verify(mIkeSession, never()).kill(); + } + + @Test + public void testSameNetworkDoesNotTriggerReconnect() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testChildSessionClosedTriggersDisconnect() throws Exception { + getChildSessionCallback().onClosed(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + } + + @Test + public void testIkeSessionClosedTriggersDisconnect() throws Exception { + getIkeSessionCallback().onClosed(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 346785907f..b4d39bf74a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -32,6 +32,7 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; @@ -117,4 +118,11 @@ public class VcnGatewayConnectionTestBase { verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any()); return captor.getValue(); } + + protected ChildSessionCallback getChildSessionCallback() { + ArgumentCaptor captor = + ArgumentCaptor.forClass(ChildSessionCallback.class); + verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture()); + return captor.getValue(); + } } From 64de6994fcd4c05cf432e481717e389eaffa6696 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 17 Dec 2020 13:57:41 -0800 Subject: [PATCH 0038/1057] Allow system components to request underlying network policies. This CL updates VcnManager to allow system components with permission NETWORK_FACTORY to request the current VcnUnderlingNetworkPolicy for a specific Network's NetworkCapabilities and LinkProperties. Bug: 175900686 Test: atest FrameworksVcnTests Change-Id: I16416e619bdb03630582f5660260b0090730e9eb --- .../net/vcn/IVcnManagementService.aidl | 4 ++ .../src/android/net/vcn/VcnManager.java | 35 ++++++++++++++- .../android/server/VcnManagementService.java | 28 +++++++++++- .../java/android/net/vcn/VcnManagerTest.java | 29 ++++++++++++ .../server/VcnManagementServiceTest.java | 45 +++++++++++++++---- 5 files changed, 130 insertions(+), 11 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 80ac64b87d..4f293eeb3c 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -16,8 +16,11 @@ package android.net.vcn; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.ParcelUuid; /** @@ -29,4 +32,5 @@ interface IVcnManagementService { void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); + VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 2d0a6d74cb..33beb6a9d1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -21,6 +21,8 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -62,7 +64,7 @@ import java.util.concurrent.Executor; * @hide */ @SystemService(Context.VCN_MANAGEMENT_SERVICE) -public final class VcnManager { +public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); /** @hide */ @@ -222,6 +224,37 @@ public final class VcnManager { } } + /** + * Queries the underlying network policy for a network with the given parameters. + * + *

    Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy + * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network + * Provider MUST poll for the updated Network policy based on that Network's capabilities and + * properties. + * + * @param networkCapabilities the NetworkCapabilities to be used in determining the Network + * policy for this Network. + * @param linkProperties the LinkProperties to be used in determining the Network policy for + * this Network. + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @return the VcnUnderlyingNetworkPolicy to be used for this Network. + * @hide + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy( + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties) { + requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + requireNonNull(linkProperties, "linkProperties must not be null"); + + try { + return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System * Server. diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 76db0192cb..8562b0d9cb 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -25,9 +25,12 @@ import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -527,7 +530,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - mContext.enforceCallingPermission( + mContext.enforceCallingOrSelfPermission( android.Manifest.permission.NETWORK_FACTORY, "Must have permission NETWORK_FACTORY to register a policy listener"); @@ -561,4 +564,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } } + + /** + * Gets the UnderlyingNetworkPolicy as determined by the provided NetworkCapabilities and + * LinkProperties. + */ + @NonNull + @Override + public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy( + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties) { + requireNonNull(networkCapabilities, "networkCapabilities was null"); + requireNonNull(linkProperties, "linkProperties was null"); + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_FACTORY, + "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" + + " Network policies"); + + // TODO(b/175914059): implement policy generation once VcnManagementService is able to + // determine policies + + return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); + } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 9c6b7194af..f9db408462 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -18,14 +18,19 @@ package android.net.vcn; import static androidx.test.InstrumentationRegistry.getContext; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; import org.junit.Before; @@ -103,4 +108,28 @@ public class VcnManagerTest { public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() { mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null); } + + @Test + public void testGetUnderlyingNetworkPolicy() throws Exception { + NetworkCapabilities nc = new NetworkCapabilities(); + LinkProperties lp = new LinkProperties(); + when(mMockVcnManagementService.getUnderlyingNetworkPolicy(eq(nc), eq(lp))) + .thenReturn(new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, nc)); + + VcnUnderlyingNetworkPolicy policy = mVcnManager.getUnderlyingNetworkPolicy(nc, lp); + + assertFalse(policy.isTeardownRequested()); + assertEquals(nc, policy.getMergedNetworkCapabilities()); + verify(mMockVcnManagementService).getUnderlyingNetworkPolicy(eq(nc), eq(lp)); + } + + @Test(expected = NullPointerException.class) + public void testGetUnderlyingNetworkPolicyNullNetworkCapabilities() throws Exception { + mVcnManager.getUnderlyingNetworkPolicy(null, new LinkProperties()); + } + + @Test(expected = NullPointerException.class) + public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception { + mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null); + } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index f0cdde33f8..e26bf19488 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -21,6 +21,8 @@ import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubsc import static com.android.server.vcn.VcnTestUtils.setupSystemService; 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; @@ -41,9 +43,12 @@ import static org.mockito.Mockito.verify; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -63,6 +68,7 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -192,6 +198,14 @@ public class VcnManagementServiceTest { mTestLooper.dispatchAll(); } + @Before + public void setUp() { + doNothing() + .when(mMockContext) + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); + } + private void setupMockedCarrierPrivilege(boolean isPrivileged) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) @@ -455,10 +469,6 @@ public class VcnManagementServiceTest { @Test public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception { - doNothing() - .when(mMockContext) - .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); - mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); verify(mMockIBinder).linkToDeath(any(), anyInt()); @@ -468,17 +478,14 @@ public class VcnManagementServiceTest { public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() { doThrow(new SecurityException()) .when(mMockContext) - .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } @Test public void testRemoveVcnUnderlyingNetworkPolicyListener() { - // verify listener added - doNothing() - .when(mMockContext) - .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -488,4 +495,24 @@ public class VcnManagementServiceTest { public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } + + @Test + public void testGetUnderlyingNetworkPolicy() throws Exception { + VcnUnderlyingNetworkPolicy policy = + mVcnMgmtSvc.getUnderlyingNetworkPolicy( + new NetworkCapabilities(), new LinkProperties()); + + assertFalse(policy.isTeardownRequested()); + assertNotNull(policy.getMergedNetworkCapabilities()); + } + + @Test(expected = SecurityException.class) + public void testGetUnderlyingNetworkPolicyInvalidPermission() { + doThrow(new SecurityException()) + .when(mMockContext) + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties()); + } } From 1eec167500a56d69f53c1642eaa08155f1113cb0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 29 Jan 2021 14:37:08 -0800 Subject: [PATCH 0039/1057] Remove usages of hidden connectivity APIs This patch updates all VCN code to use System or Public APIs for connectivity management (NetworkCapabilities, NetworkRequests, etc). Bug: 8675309 Test: atest FrameworksVcnTests Change-Id: I6637e1ca7efaff64d3e11187120ad9b42bdce45c --- .../src/com/android/server/vcn/Vcn.java | 13 ++++++------ .../server/vcn/VcnGatewayConnection.java | 12 +++++------ .../server/vcn/VcnNetworkProvider.java | 20 +++++++++++++------ 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 9d21b9241c..132883e4a0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -168,8 +168,8 @@ public class Vcn extends Handler { @NonNull NetworkRequest request, int score, int providerId) { if (score > getNetworkScore()) { Slog.v(getLogTag(), - "Request " + request.requestId + " already satisfied by higher-scoring (" - + score + ") network from provider " + providerId); + "Request already satisfied by higher-scoring (" + score + ") network from " + + "provider " + providerId + ": " + request); return; } @@ -177,8 +177,7 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { Slog.v(getLogTag(), - "Request " + request.requestId - + " satisfied by existing VcnGatewayConnection"); + "Request already satisfied by existing VcnGatewayConnection: " + request); return; } } @@ -202,12 +201,12 @@ public class Vcn extends Handler { private boolean requestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { - final NetworkCapabilities configCaps = new NetworkCapabilities(); + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); for (int cap : config.getAllExposedCapabilities()) { - configCaps.addCapability(cap); + builder.addCapability(cap); } - return request.networkCapabilities.satisfiedByNetworkCapabilities(configCaps); + return request.canBeSatisfiedBy(builder.build()); } private String getLogTag() { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 703bfab6d8..3cfa00eb60 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -963,18 +963,18 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { - final NetworkCapabilities caps = new NetworkCapabilities(); + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); - caps.addTransportType(TRANSPORT_CELLULAR); - caps.addCapability(NET_CAPABILITY_NOT_CONGESTED); - caps.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + builder.addTransportType(TRANSPORT_CELLULAR); + builder.addCapability(NET_CAPABILITY_NOT_CONGESTED); + builder.addCapability(NET_CAPABILITY_NOT_SUSPENDED); // Add exposed capabilities for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) { - caps.addCapability(cap); + builder.addCapability(cap); } - return caps; + return builder.build(); } private static LinkProperties buildConnectedLinkProperties( diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 7f5b23c9db..b9babae4c6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -21,9 +21,9 @@ import android.content.Context; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.os.Looper; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; -import android.util.SparseArray; import java.util.Objects; import java.util.Set; @@ -40,7 +40,13 @@ public class VcnNetworkProvider extends NetworkProvider { private static final String TAG = VcnNetworkProvider.class.getSimpleName(); private final Set mListeners = new ArraySet<>(); - private final SparseArray mRequests = new SparseArray<>(); + + /** + * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest + * + *

    NetworkRequests are immutable once created, and therefore can be used as stable keys. + */ + private final ArrayMap mRequests = new ArrayMap<>(); public VcnNetworkProvider(Context context, Looper looper) { super(context, looper, VcnNetworkProvider.class.getSimpleName()); @@ -51,8 +57,8 @@ public class VcnNetworkProvider extends NetworkProvider { mListeners.add(listener); // Send listener all cached requests - for (int i = 0; i < mRequests.size(); i++) { - notifyListenerForEvent(listener, mRequests.valueAt(i)); + for (NetworkRequestEntry entry : mRequests.values()) { + notifyListenerForEvent(listener, entry); } } @@ -75,7 +81,9 @@ public class VcnNetworkProvider extends NetworkProvider { request, score, providerId)); final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId); - mRequests.put(request.requestId, entry); + + // NetworkRequests are immutable once created, and therefore can be used as stable keys. + mRequests.put(request, entry); // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on // Default Data Sub, or similar) @@ -86,7 +94,7 @@ public class VcnNetworkProvider extends NetworkProvider { @Override public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - mRequests.remove(request.requestId); + mRequests.remove(request); } private static class NetworkRequestEntry { From 56a8ca7f9f60a38a811d424dd622b5d56aecf298 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 12 Jan 2021 15:01:33 -0800 Subject: [PATCH 0040/1057] Register NetworkCallbacks in UnderlyingNetworkTracker. This CL updates UnderlyingNetworkTracker to register NetworkCallbacks. UnderlyingNetworkTracker uses two types of NetworkCallbacks: - bringup requests - selection requests Bringup requests ensure that VCN-managed Networks are not reaped. Separate bringup requests are filed for wifi and cell Networks. One cell request is filed for each subscription ID (subId) in the VCN's subscription group. Selection requests are used to allow ConnectivityService to perform Network selection for the VCN's selected underlying Network (the Network that VCN traffic will be routed through). Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: Ic4dc13a3f7acf08589ddb25b343af2677cd7cf65 --- .../src/android/net/vcn/VcnManager.java | 1 - .../server/vcn/UnderlyingNetworkTracker.java | 367 +++++++++++++++++- .../com/android/server/vcn/VcnContext.java | 11 + .../server/vcn/VcnGatewayConnection.java | 10 +- .../vcn/VcnGatewayConnectionTestBase.java | 2 +- 5 files changed, 376 insertions(+), 15 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 33beb6a9d1..fa090f59a8 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -67,7 +67,6 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - /** @hide */ @VisibleForTesting public static final Map< VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 6427ae2dc1..fd12c2d2eb 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -18,16 +18,28 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkCapabilities.NetCapability; +import android.net.NetworkRequest; +import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.os.ParcelUuid; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.util.ArraySet; +import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import java.util.List; import java.util.Objects; +import java.util.Set; /** * Tracks a set of Networks underpinning a VcnGatewayConnection. @@ -38,53 +50,385 @@ import java.util.Objects; * * @hide */ -public class UnderlyingNetworkTracker extends Handler { +public class UnderlyingNetworkTracker { @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final Dependencies mDeps; + @NonNull private final Handler mHandler; + @NonNull private final ConnectivityManager mConnectivityManager; + @NonNull private final SubscriptionManager mSubscriptionManager; + + @NonNull private final SparseArray mCellBringupCallbacks = new SparseArray<>(); + @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback(); + @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); + + @NonNull private final Set mSubIds = new ArraySet<>(); + + @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; + + @Nullable private UnderlyingNetworkRecord mCurrentRecord; + @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; public UnderlyingNetworkTracker( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb) { - this(vcnContext, subscriptionGroup, cb, new Dependencies()); + this( + vcnContext, + subscriptionGroup, + requiredUnderlyingNetworkCapabilities, + cb, + new Dependencies()); } private UnderlyingNetworkTracker( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb, @NonNull Dependencies deps) { - super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); - mVcnContext = vcnContext; + mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mRequiredUnderlyingNetworkCapabilities = + Objects.requireNonNull( + requiredUnderlyingNetworkCapabilities, + "Missing requiredUnderlyingNetworkCapabilities"); mCb = Objects.requireNonNull(cb, "Missing cb"); mDeps = Objects.requireNonNull(deps, "Missing deps"); + + mHandler = new Handler(mVcnContext.getLooper()); + + mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); + mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class); + + registerNetworkRequests(); + } + + private void registerNetworkRequests() { + // register bringup requests for underlying Networks + mConnectivityManager.requestBackgroundNetwork( + getWifiNetworkRequest(), mHandler, mWifiBringupCallback); + updateSubIdsAndCellularRequests(); + + // register Network-selection request used to decide selected underlying Network + mConnectivityManager.requestBackgroundNetwork( + getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback); + } + + private NetworkRequest getWifiNetworkRequest() { + return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + } + + private NetworkRequest getCellNetworkRequestForSubId(int subId) { + return getNetworkRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) + .build(); + } + + private NetworkRequest.Builder getNetworkRequestBase() { + NetworkRequest.Builder requestBase = new NetworkRequest.Builder(); + for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) { + requestBase.addCapability(capability); + } + + return requestBase + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + /** + * Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker. + */ + private void updateSubIdsAndCellularRequests() { + mVcnContext.ensureRunningOnLooperThread(); + + Set prevSubIds = new ArraySet<>(mSubIds); + mSubIds.clear(); + + // Ensure NetworkRequests filed for all current subIds in mSubscriptionGroup + // STOPSHIP: b/177364490 use TelephonySubscriptionSnapshot to avoid querying Telephony + List subInfos = + mSubscriptionManager.getSubscriptionsInGroup(mSubscriptionGroup); + + for (SubscriptionInfo subInfo : subInfos) { + final int subId = subInfo.getSubscriptionId(); + mSubIds.add(subId); + + if (!mCellBringupCallbacks.contains(subId)) { + final NetworkBringupCallback cb = new NetworkBringupCallback(); + mCellBringupCallbacks.put(subId, cb); + + mConnectivityManager.requestBackgroundNetwork( + getCellNetworkRequestForSubId(subId), mHandler, cb); + } + } + + // unregister all NetworkCallbacks for outdated subIds + for (final int subId : prevSubIds) { + if (!mSubIds.contains(subId)) { + final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId); + mConnectivityManager.unregisterNetworkCallback(cb); + } + } } /** Tears down this Tracker, and releases all underlying network requests. */ - public void teardown() {} + public void teardown() { + mVcnContext.ensureRunningOnLooperThread(); - /** An record of a single underlying network, caching relevant fields. */ + mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback); + mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback); + + for (final int subId : mSubIds) { + final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId); + mConnectivityManager.unregisterNetworkCallback(cb); + } + mSubIds.clear(); + } + + /** Returns whether the currently selected Network matches the given network. */ + private static boolean isSameNetwork( + @Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) { + return recordInProgress != null && recordInProgress.getNetwork().equals(network); + } + + /** Notify the Callback if a full UnderlyingNetworkRecord exists. */ + private void maybeNotifyCallback() { + // Only forward this update if a complete record has been received + if (!mRecordInProgress.isValid()) { + return; + } + + // Only forward this update if the updated record differs form the current record + UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build(); + if (!updatedRecord.equals(mCurrentRecord)) { + mCurrentRecord = updatedRecord; + + mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); + } + } + + private void handleNetworkAvailable(@NonNull Network network) { + mVcnContext.ensureRunningOnLooperThread(); + + mRecordInProgress = new UnderlyingNetworkRecord.Builder(network); + } + + private void handleNetworkLost(@NonNull Network network) { + mVcnContext.ensureRunningOnLooperThread(); + + if (!isSameNetwork(mRecordInProgress, network)) { + Slog.wtf(TAG, "Non-underlying Network lost"); + return; + } + + mRecordInProgress = null; + mCurrentRecord = null; + mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */); + } + + private void handleCapabilitiesChanged( + @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + mVcnContext.ensureRunningOnLooperThread(); + + if (!isSameNetwork(mRecordInProgress, network)) { + Slog.wtf(TAG, "Invalid update to NetworkCapabilities"); + return; + } + + mRecordInProgress.setNetworkCapabilities(networkCapabilities); + + maybeNotifyCallback(); + } + + private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) { + mVcnContext.ensureRunningOnLooperThread(); + + if (!isSameNetwork(mRecordInProgress, network)) { + Slog.wtf(TAG, "Invalid update to isSuspended"); + return; + } + + final NetworkCapabilities newCaps = + new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities()); + if (isSuspended) { + newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + } else { + newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + } + + handleCapabilitiesChanged(network, newCaps); + } + + private void handlePropertiesChanged( + @NonNull Network network, @NonNull LinkProperties linkProperties) { + mVcnContext.ensureRunningOnLooperThread(); + + if (!isSameNetwork(mRecordInProgress, network)) { + Slog.wtf(TAG, "Invalid update to LinkProperties"); + return; + } + + mRecordInProgress.setLinkProperties(linkProperties); + + maybeNotifyCallback(); + } + + private void handleNetworkBlocked(@NonNull Network network, boolean isBlocked) { + mVcnContext.ensureRunningOnLooperThread(); + + if (!isSameNetwork(mRecordInProgress, network)) { + Slog.wtf(TAG, "Invalid update to isBlocked"); + return; + } + + mRecordInProgress.setIsBlocked(isBlocked); + + maybeNotifyCallback(); + } + + /** + * NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped. + * + *

    NetworkBringupCallback only exists to prevent matching (VCN-managed) Networks from being + * reaped, and no action is taken on any events firing. + */ + @VisibleForTesting + class NetworkBringupCallback extends NetworkCallback {} + + /** + * RouteSelectionCallback is used to select the "best" underlying Network. + * + *

    The "best" network is determined by ConnectivityService, which is treated as a source of + * truth. + */ + @VisibleForTesting + class RouteSelectionCallback extends NetworkCallback { + @Override + public void onAvailable(@NonNull Network network) { + handleNetworkAvailable(network); + } + + @Override + public void onLost(@NonNull Network network) { + handleNetworkLost(network); + } + + @Override + public void onCapabilitiesChanged( + @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + handleCapabilitiesChanged(network, networkCapabilities); + } + + @Override + public void onNetworkSuspended(@NonNull Network network) { + handleNetworkSuspended(network, true /* isSuspended */); + } + + @Override + public void onNetworkResumed(@NonNull Network network) { + handleNetworkSuspended(network, false /* isSuspended */); + } + + @Override + public void onLinkPropertiesChanged( + @NonNull Network network, @NonNull LinkProperties linkProperties) { + handlePropertiesChanged(network, linkProperties); + } + + @Override + public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { + handleNetworkBlocked(network, isBlocked); + } + } + + /** A record of a single underlying network, caching relevant fields. */ public static class UnderlyingNetworkRecord { @NonNull public final Network network; @NonNull public final NetworkCapabilities networkCapabilities; @NonNull public final LinkProperties linkProperties; - public final boolean blocked; + public final boolean isBlocked; @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, - boolean blocked) { + boolean isBlocked) { this.network = network; this.networkCapabilities = networkCapabilities; this.linkProperties = linkProperties; - this.blocked = blocked; + this.isBlocked = isBlocked; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UnderlyingNetworkRecord)) return false; + final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o; + + return network.equals(that.network) + && networkCapabilities.equals(that.networkCapabilities) + && linkProperties.equals(that.linkProperties) + && isBlocked == that.isBlocked; + } + + @Override + public int hashCode() { + return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); + } + + /** Builder to incrementally construct an UnderlyingNetworkRecord. */ + private static class Builder { + @NonNull private final Network mNetwork; + + @Nullable private NetworkCapabilities mNetworkCapabilities; + @Nullable private LinkProperties mLinkProperties; + boolean mIsBlocked; + boolean mWasIsBlockedSet; + + private Builder(@NonNull Network network) { + mNetwork = network; + } + + @NonNull + private Network getNetwork() { + return mNetwork; + } + + private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + mNetworkCapabilities = networkCapabilities; + } + + @Nullable + private NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + private void setLinkProperties(@NonNull LinkProperties linkProperties) { + mLinkProperties = linkProperties; + } + + private void setIsBlocked(boolean isBlocked) { + mIsBlocked = isBlocked; + mWasIsBlockedSet = true; + } + + private boolean isValid() { + return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; + } + + private UnderlyingNetworkRecord build() { + return new UnderlyingNetworkRecord( + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + } } } @@ -95,9 +439,10 @@ public class UnderlyingNetworkTracker extends Handler { * *

    This callback does NOT signal a mobility event. * - * @param underlying The details of the new underlying network + * @param underlyingNetworkRecord The details of the new underlying network */ - void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying); + void onSelectedUnderlyingNetworkChanged( + @Nullable UnderlyingNetworkRecord underlyingNetworkRecord); } private static class Dependencies {} diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index dba59bdbee..7399e56b3a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -55,4 +55,15 @@ public class VcnContext { public VcnNetworkProvider getVcnNetworkProvider() { return mVcnNetworkProvider; } + + /** + * Verifies that the caller is running on the VcnContext Thread. + * + * @throwsIllegalStateException if the caller is not running on the VcnContext Thread. + */ + public void ensureRunningOnLooperThread() { + if (getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException("Not running on VcnMgmtSvc thread"); + } + } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 3cfa00eb60..39c96069f9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -65,6 +65,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -476,7 +477,10 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkTracker = mDeps.newUnderlyingNetworkTracker( - mVcnContext, subscriptionGroup, mUnderlyingNetworkTrackerCallback); + mVcnContext, + subscriptionGroup, + mConnectionConfig.getAllUnderlyingCapabilities(), + mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); IpSecTunnelInterface iface; @@ -1134,8 +1138,10 @@ public class VcnGatewayConnection extends StateMachine { public UnderlyingNetworkTracker newUnderlyingNetworkTracker( VcnContext vcnContext, ParcelUuid subscriptionGroup, + Set requiredUnderlyingNetworkCapabilities, UnderlyingNetworkTrackerCallback callback) { - return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback); + return new UnderlyingNetworkTracker( + vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback); } /** Builds a new IkeSession. */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index b4d39bf74a..4d92fb9c42 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -94,7 +94,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any()); + .newUnderlyingNetworkTracker(any(), any(), any(), any()); } @Before From 2214eef353a6ba07b3a53a1b95c991dc206e3d54 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 14 Jan 2021 12:57:15 -0800 Subject: [PATCH 0041/1057] Unit test UnderlyingNetworkTracker. Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: I681b0bef27cdd1974a574e81b4b435578cd6e9cd --- .../vcn/UnderlyingNetworkTrackerTest.java | 366 ++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java new file mode 100644 index 0000000000..48e068d141 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -0,0 +1,366 @@ +/* + * 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.server.vcn; + +import static com.android.server.vcn.VcnTestUtils.setupSystemService; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +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.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.TelephonyNetworkSpecifier; +import android.os.ParcelUuid; +import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; + +import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; +import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +public class UnderlyingNetworkTrackerTest { + private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + private static final int INITIAL_SUB_ID_1 = 1; + private static final int INITIAL_SUB_ID_2 = 2; + + private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .build(); + private static final NetworkCapabilities SUSPENDED_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder(INITIAL_NETWORK_CAPABILITIES) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .build(); + private static final NetworkCapabilities UPDATED_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .build(); + + private static final LinkProperties INITIAL_LINK_PROPERTIES = + getLinkPropertiesWithName("initial_iface"); + private static final LinkProperties UPDATED_LINK_PROPERTIES = + getLinkPropertiesWithName("updated_iface"); + + @Mock private Context mContext; + @Mock private VcnNetworkProvider mVcnNetworkProvider; + @Mock private ConnectivityManager mConnectivityManager; + @Mock private SubscriptionManager mSubscriptionManager; + @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; + @Mock private Network mNetwork; + + @Captor private ArgumentCaptor mRouteSelectionCallbackCaptor; + + private TestLooper mTestLooper; + private VcnContext mVcnContext; + private UnderlyingNetworkTracker mUnderlyingNetworkTracker; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mTestLooper = new TestLooper(); + mVcnContext = spy(new VcnContext(mContext, mTestLooper.getLooper(), mVcnNetworkProvider)); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + + setupSystemService( + mContext, + mConnectivityManager, + Context.CONNECTIVITY_SERVICE, + ConnectivityManager.class); + setupSystemService( + mContext, + mSubscriptionManager, + Context.TELEPHONY_SUBSCRIPTION_SERVICE, + SubscriptionManager.class); + + List initialSubInfos = + Arrays.asList( + getSubscriptionInfoForSubId(INITIAL_SUB_ID_1), + getSubscriptionInfoForSubId(INITIAL_SUB_ID_2)); + when(mSubscriptionManager.getSubscriptionsInGroup(eq(SUB_GROUP))) + .thenReturn(initialSubInfos); + + mUnderlyingNetworkTracker = + new UnderlyingNetworkTracker( + mVcnContext, + SUB_GROUP, + Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), + mNetworkTrackerCb); + } + + private static LinkProperties getLinkPropertiesWithName(String iface) { + LinkProperties linkProperties = new LinkProperties(); + linkProperties.setInterfaceName(iface); + return linkProperties; + } + + private SubscriptionInfo getSubscriptionInfoForSubId(int subId) { + SubscriptionInfo subInfo = mock(SubscriptionInfo.class); + when(subInfo.getSubscriptionId()).thenReturn(subId); + return subInfo; + } + + @Test + public void testNetworkCallbacksRegisteredOnStartup() { + // verify NetworkCallbacks registered when instantiated + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getWifiRequest()), + any(), + any(NetworkBringupCallback.class)); + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getCellRequestForSubId(INITIAL_SUB_ID_1)), + any(), + any(NetworkBringupCallback.class)); + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getCellRequestForSubId(INITIAL_SUB_ID_2)), + any(), + any(NetworkBringupCallback.class)); + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getRouteSelectionRequest()), + any(), + any(RouteSelectionCallback.class)); + + verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP)); + } + + private NetworkRequest getWifiRequest() { + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private NetworkRequest getCellRequestForSubId(int subId) { + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) + .build(); + } + + private NetworkRequest getRouteSelectionRequest() { + return getExpectedRequestBase().build(); + } + + private NetworkRequest.Builder getExpectedRequestBase() { + return new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + @Test + public void testTeardown() { + mUnderlyingNetworkTracker.teardown(); + + // Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x + // for each subId) + verify(mConnectivityManager, times(3)) + .unregisterNetworkCallback(any(NetworkBringupCallback.class)); + verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + } + + @Test + public void testUnderlyingNetworkRecordEquals() { + UnderlyingNetworkRecord recordA = + new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + UnderlyingNetworkRecord recordB = + new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + UnderlyingNetworkRecord recordC = + new UnderlyingNetworkRecord( + mNetwork, + UPDATED_NETWORK_CAPABILITIES, + UPDATED_LINK_PROPERTIES, + false /* isBlocked */); + + assertEquals(recordA, recordB); + assertNotEquals(recordA, recordC); + } + + @Test + public void testRecordTrackerCallbackNotifiedForNetworkChange() { + verifyRegistrationOnAvailableAndGetCallback(); + } + + private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() { + return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); + } + + private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback( + NetworkCapabilities networkCapabilities) { + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getRouteSelectionRequest()), + any(), + mRouteSelectionCallbackCaptor.capture()); + + RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); + cb.onAvailable(mNetwork); + cb.onCapabilitiesChanged(mNetwork, networkCapabilities); + cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); + cb.onBlockedStatusChanged(mNetwork, false /* isFalse */); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + networkCapabilities, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + return cb; + } + + @Test + public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + UPDATED_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + + @Test + public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + UPDATED_LINK_PROPERTIES, + false /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + + @Test + public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onNetworkSuspended(mNetwork); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + SUSPENDED_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + + @Test + public void testRecordTrackerCallbackNotifiedForNetworkResumed() { + RouteSelectionCallback cb = + verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); + + cb.onNetworkResumed(mNetwork); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + + @Test + public void testRecordTrackerCallbackNotifiedForBlocked() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); + + UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + true /* isBlocked */); + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + + @Test + public void testRecordTrackerCallbackNotifiedForNetworkLoss() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onLost(mNetwork); + + verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null); + } + + @Test + public void testRecordTrackerCallbackIgnoresDuplicateRecord() { + RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + + cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + + // Verify no more calls to the UnderlyingNetworkTrackerCallback when the + // UnderlyingNetworkRecord does not actually change + verifyNoMoreInteractions(mNetworkTrackerCb); + } +} From 83c7639dfc4e16fb9a8a92707052beb6b5fcbe53 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 19 Jan 2021 15:19:15 -0800 Subject: [PATCH 0042/1057] Implement Network policy in VcnManagementService. This CL implements #getUnderlyingNetworkPolicy() for VcnManagementService. Specifically, it takes the provided NetworkCapabilities and checks for a corresponding VCN. If one exists, a VcnUnderlyingNetworkPolicy will be returned with a copy of the original NetworkCapabilities without the capability NOT_VCN_MANAGED and with the unwanted capability NOT_VCN_MANAGED. Any NetworkCapabilities without a corresponding VCN will be returned a VcnUnderlyingNetworkPolicy with the original NetworkCapabilities intact. Bug: 175914059 Test: atest FrameworksVcnTests Change-Id: Icdffc4f586f58a0e5b6290d5c6449e2bbed5cab0 --- .../android/server/VcnManagementService.java | 40 +++++++- .../server/VcnManagementServiceTest.java | 98 ++++++++++++++++--- 2 files changed, 125 insertions(+), 13 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 8562b0d9cb..6a72010738 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -27,10 +27,12 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnUnderlyingNetworkPolicy; +import android.net.wifi.WifiInfo; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -291,6 +293,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull VcnConfig config) { return new Vcn(vcnContext, subscriptionGroup, config); } + + /** Gets the subId indicated by the given {@link WifiInfo}. */ + public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) { + // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } } /** Notifies the VcnManagementService that external dependencies can be set up. */ @@ -582,8 +590,36 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" + " Network policies"); - // TODO(b/175914059): implement policy generation once VcnManagementService is able to - // determine policies + // Defensive copy in case this call is in-process and the given NetworkCapabilities mutates + networkCapabilities = new NetworkCapabilities(networkCapabilities); + + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) + && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { + TelephonyNetworkSpecifier telephonyNetworkSpecifier = + (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); + subId = telephonyNetworkSpecifier.getSubscriptionId(); + } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + && networkCapabilities.getTransportInfo() instanceof WifiInfo) { + WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); + subId = mDeps.getSubIdForWifiInfo(wifiInfo); + } + + boolean isVcnManagedNetwork = false; + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + synchronized (mLock) { + ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); + + // TODO(b/178140910): only mark the Network as VCN-managed if not in safe mode + if (mVcns.containsKey(subGroup)) { + isVcnManagedNetwork = true; + } + } + } + if (isVcnManagedNetwork) { + networkCapabilities.removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index e26bf19488..e7d334ebd4 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -22,7 +22,6 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService; 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; @@ -30,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -39,16 +39,20 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; +import android.net.NetworkCapabilities.Transport; +import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; import android.net.vcn.VcnUnderlyingNetworkPolicy; +import android.net.wifi.WifiInfo; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -253,7 +257,14 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).readFromDisk(); } - private void triggerSubscriptionTrackerCallback(Set activeSubscriptionGroups) { + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + Set activeSubscriptionGroups) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + activeSubscriptionGroups, Collections.emptyMap()); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + Set activeSubscriptionGroups, Map subIdToGroupMap) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); @@ -267,8 +278,14 @@ public class VcnManagementServiceTest { argThat(val -> activeSubscriptionGroups.contains(val)), eq(TEST_PACKAGE_NAME)); + doAnswer(invocation -> { + return subIdToGroupMap.get(invocation.getArgument(0)); + }).when(snapshot).getGroupForSubId(anyInt()); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); cb.onNewSnapshot(snapshot); + + return snapshot; } private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() { @@ -287,7 +304,7 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { - triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG)); } @@ -296,7 +313,7 @@ public class VcnManagementServiceTest { final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); - triggerSubscriptionTrackerCallback(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); // Verify teardown after delay mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -311,13 +328,13 @@ public class VcnManagementServiceTest { final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCallback(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); // Simulate new SIM loaded right during teardown delay. mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); // Verify that even after the full timeout duration, the VCN instance is not torn down mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -331,7 +348,7 @@ public class VcnManagementServiceTest { final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCallback(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new // vcnInstance. @@ -496,14 +513,73 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } + private void setUpVcnSubscription(int subId, ParcelUuid subGroup) { + mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup)); + } + + private void verifyMergedNetworkCapabilities( + NetworkCapabilities mergedCapabilities, @Transport int transportType) { + assertTrue(mergedCapabilities.hasTransport(transportType)); + assertFalse( + mergedCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); + } + @Test - public void testGetUnderlyingNetworkPolicy() throws Exception { + public void testGetUnderlyingNetworkPolicyTransportCell() throws Exception { + setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); + + NetworkCapabilities nc = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)) + .build(); + VcnUnderlyingNetworkPolicy policy = - mVcnMgmtSvc.getUnderlyingNetworkPolicy( - new NetworkCapabilities(), new LinkProperties()); + mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); assertFalse(policy.isTeardownRequested()); - assertNotNull(policy.getMergedNetworkCapabilities()); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR); + } + + @Test + public void testGetUnderlyingNetworkPolicyTransportWifi() throws Exception { + setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); + + WifiInfo wifiInfo = mock(WifiInfo.class); + when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); + when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); + NetworkCapabilities nc = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setTransportInfo(wifiInfo) + .build(); + + VcnUnderlyingNetworkPolicy policy = + mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); + + assertFalse(policy.isTeardownRequested()); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI); + } + + @Test + public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception { + NetworkCapabilities nc = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)) + .build(); + + VcnUnderlyingNetworkPolicy policy = + mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); + + assertFalse(policy.isTeardownRequested()); + assertEquals(nc, policy.getMergedNetworkCapabilities()); } @Test(expected = SecurityException.class) From 6fbf23e095494d9069fc2f352e37d38a7767fde1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 12 Jan 2021 01:56:33 -0800 Subject: [PATCH 0043/1057] Implement ConnectedState This change implements the Connected state, ensuring that relevant capabilities are mirrored from the underlying networks. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: Iedf6d879b4577d7efd40cce41cc1d5fd5021124f --- .../src/com/android/server/vcn/Vcn.java | 3 +- .../server/vcn/VcnGatewayConnection.java | 252 +++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 127 +++++++++ .../server/vcn/VcnGatewayConnectionTest.java | 67 ++++- .../vcn/VcnGatewayConnectionTestBase.java | 11 +- 5 files changed, 448 insertions(+), 12 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 132883e4a0..fd19322cec 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -214,7 +214,8 @@ public class Vcn extends Handler { } /** Retrieves the network score for a VCN Network */ - private int getNetworkScore() { + // Package visibility for use in VcnGatewayConnection + static int getNetworkScore() { // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in // subGrp" value return 52; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 39c96069f9..db372270fe 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -17,8 +17,11 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static com.android.server.VcnManagementService.VDBG; @@ -34,8 +37,10 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; +import android.net.TelephonyNetworkSpecifier; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; @@ -47,10 +52,13 @@ import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnTransportInfo; +import android.net.wifi.WifiInfo; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -64,6 +72,7 @@ import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -113,6 +122,9 @@ import java.util.concurrent.TimeUnit; public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + private static final int[] MERGED_CAPABILITIES = + new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING}; + private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE; @@ -537,6 +549,8 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onSelectedUnderlyingNetworkChanged( @Nullable UnderlyingNetworkRecord underlying) { + // TODO(b/179091925): Move the delayed-message handling to BaseState + // If underlying is null, all underlying networks have been lost. Disconnect VCN after a // timeout. if (underlying == null) { @@ -921,6 +935,8 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mDisconnectingState); break; case EVENT_SESSION_CLOSED: + // Disconnecting state waits for EVENT_SESSION_CLOSED to shutdown, and this + // message may not be posted again. Defer to ensure immediate shutdown. deferMessage(msg); transitionTo(mDisconnectingState); @@ -941,7 +957,108 @@ public class VcnGatewayConnection extends StateMachine { } } - private abstract class ConnectedStateBase extends ActiveBaseState {} + private abstract class ConnectedStateBase extends ActiveBaseState { + protected void updateNetworkAgent( + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull NetworkAgent agent, + @NonNull ChildSessionConfiguration childConfig) { + final NetworkCapabilities caps = + buildNetworkCapabilities(mConnectionConfig, mUnderlying); + final LinkProperties lp = + buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); + + agent.sendNetworkCapabilities(caps); + agent.sendLinkProperties(lp); + } + + protected NetworkAgent buildNetworkAgent( + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull ChildSessionConfiguration childConfig) { + final NetworkCapabilities caps = + buildNetworkCapabilities(mConnectionConfig, mUnderlying); + final LinkProperties lp = + buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); + + final NetworkAgent agent = + new NetworkAgent( + mVcnContext.getContext(), + mVcnContext.getLooper(), + TAG, + caps, + lp, + Vcn.getNetworkScore(), + new NetworkAgentConfig(), + mVcnContext.getVcnNetworkProvider()) { + @Override + public void unwanted() { + teardownAsynchronously(); + } + }; + + agent.register(); + agent.markConnected(); + + return agent; + } + + protected void applyTransform( + int token, + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull Network underlyingNetwork, + @NonNull IpSecTransform transform, + int direction) { + try { + // TODO: Set underlying network of tunnel interface + + // Transforms do not need to be persisted; the IkeSession will keep them alive + mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); + } catch (IOException e) { + Slog.d(TAG, "Transform application failed for network " + token, e); + sessionLost(token, e); + } + } + + protected void setupInterface( + int token, + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull ChildSessionConfiguration childConfig) { + setupInterface(token, tunnelIface, childConfig, null); + } + + protected void setupInterface( + int token, + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull ChildSessionConfiguration childConfig, + @Nullable ChildSessionConfiguration oldChildConfig) { + try { + final Set newAddrs = + new ArraySet<>(childConfig.getInternalAddresses()); + final Set existingAddrs = new ArraySet<>(); + if (oldChildConfig != null) { + existingAddrs.addAll(oldChildConfig.getInternalAddresses()); + } + + final Set toAdd = new ArraySet<>(); + toAdd.addAll(newAddrs); + toAdd.removeAll(existingAddrs); + + final Set toRemove = new ArraySet<>(); + toRemove.addAll(existingAddrs); + toRemove.removeAll(newAddrs); + + for (LinkAddress address : toAdd) { + tunnelIface.addAddress(address.getAddress(), address.getPrefixLength()); + } + + for (LinkAddress address : toRemove) { + tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength()); + } + } catch (IOException e) { + Slog.d(TAG, "Adding address to tunnel failed for token " + token, e); + sessionLost(token, e); + } + } + } /** * Stable state representing a VCN that has a functioning connection to the mobility anchor. @@ -951,7 +1068,89 @@ public class VcnGatewayConnection extends StateMachine { */ class ConnectedState extends ConnectedStateBase { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() throws Exception { + // Successful connection, clear failed attempt counter + mFailedAttempts = 0; + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: + handleUnderlyingNetworkChanged(msg); + break; + case EVENT_SESSION_CLOSED: + // Disconnecting state waits for EVENT_SESSION_CLOSED to shutdown, and this + // message may not be posted again. Defer to ensure immediate shutdown. + deferMessage(msg); + transitionTo(mDisconnectingState); + break; + case EVENT_SESSION_LOST: + transitionTo(mDisconnectingState); + break; + case EVENT_TRANSFORM_CREATED: + final EventTransformCreatedInfo transformCreatedInfo = + (EventTransformCreatedInfo) msg.obj; + + applyTransform( + mCurrentToken, + mTunnelIface, + mUnderlying.network, + transformCreatedInfo.transform, + transformCreatedInfo.direction); + break; + case EVENT_SETUP_COMPLETED: + mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig; + + setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); + break; + case EVENT_DISCONNECT_REQUESTED: + handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + break; + default: + logUnhandledMessage(msg); + break; + } + } + + private void handleUnderlyingNetworkChanged(@NonNull Message msg) { + final UnderlyingNetworkRecord oldUnderlying = mUnderlying; + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + if (mUnderlying == null) { + // Ignored for now; a new network may be coming up. If none does, the delayed + // NETWORK_LOST disconnect will be fired, and tear down the session + network. + return; + } + + // mUnderlying assumed non-null, given check above. + // If network changed, migrate. Otherwise, update any existing networkAgent. + if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) { + mIkeSession.setNetwork(mUnderlying.network); + } else { + // oldUnderlying is non-null & underlying network itself has not changed + // (only network properties were changed). + + // Network not yet set up, or child not yet connected. + if (mNetworkAgent != null && mChildConfig != null) { + // If only network properties changed and agent is active, update properties + updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + } + } + } + + protected void setupInterfaceAndNetworkAgent( + int token, + @NonNull IpSecTunnelInterface tunnelIface, + @NonNull ChildSessionConfiguration childConfig) { + setupInterface(token, tunnelIface, childConfig); + + if (mNetworkAgent == null) { + mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig); + } else { + updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig); + } + } } /** @@ -966,7 +1165,8 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( - @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { + @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, + @Nullable UnderlyingNetworkRecord underlying) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); @@ -978,6 +1178,52 @@ public class VcnGatewayConnection extends StateMachine { builder.addCapability(cap); } + if (underlying != null) { + final NetworkCapabilities underlyingCaps = underlying.networkCapabilities; + + // Mirror merged capabilities. + for (int cap : MERGED_CAPABILITIES) { + if (underlyingCaps.hasCapability(cap)) { + builder.addCapability(cap); + } + } + + // Set admin UIDs for ConnectivityDiagnostics use. + final int[] underlyingAdminUids = underlyingCaps.getAdministratorUids(); + Arrays.sort(underlyingAdminUids); // Sort to allow contains check below. + + final int[] adminUids; + if (underlyingCaps.getOwnerUid() > 0 // No owner UID specified + && 0 > Arrays.binarySearch(// Owner UID not found in admin UID list. + underlyingAdminUids, underlyingCaps.getOwnerUid())) { + adminUids = Arrays.copyOf(underlyingAdminUids, underlyingAdminUids.length + 1); + adminUids[adminUids.length - 1] = underlyingCaps.getOwnerUid(); + Arrays.sort(adminUids); + } else { + adminUids = underlyingAdminUids; + } + builder.setAdministratorUids(adminUids); + + // Set TransportInfo for SysUI use (never parcelled out of SystemServer). + if (underlyingCaps.hasTransport(TRANSPORT_WIFI) + && underlyingCaps.getTransportInfo() instanceof WifiInfo) { + final WifiInfo wifiInfo = (WifiInfo) underlyingCaps.getTransportInfo(); + builder.setTransportInfo(new VcnTransportInfo(wifiInfo)); + } else if (underlyingCaps.hasTransport(TRANSPORT_CELLULAR) + && underlyingCaps.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { + final TelephonyNetworkSpecifier telNetSpecifier = + (TelephonyNetworkSpecifier) underlyingCaps.getNetworkSpecifier(); + builder.setTransportInfo(new VcnTransportInfo(telNetSpecifier.getSubscriptionId())); + } else { + Slog.wtf( + TAG, + "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + + " non-null underlying network"); + } + } + + // TODO: Make a VcnNetworkSpecifier, and match all underlying subscription IDs. + return builder.build(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java new file mode 100644 index 0000000000..e20070ee4f --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -0,0 +1,127 @@ +/* + * 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.vcn; + +import static android.net.IpSecManager.DIRECTION_IN; +import static android.net.IpSecManager.DIRECTION_OUT; + +import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for VcnGatewayConnection.ConnectedState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { + private VcnIkeSession mIkeSession; + + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); + + mIkeSession = mGatewayConnection.buildIkeSession(); + mGatewayConnection.setIkeSession(mIkeSession); + + mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState); + mTestLooper.dispatchAll(); + } + + @Test + public void testEnterStateCreatesNewIkeSession() throws Exception { + verify(mDeps).newIkeSession(any(), any(), any(), any(), any()); + } + + @Test + public void testNullNetworkDoesNotTriggerDisconnect() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + verify(mIkeSession, never()).close(); + } + + @Test + public void testNewNetworkTriggersMigration() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + verify(mIkeSession, never()).close(); + verify(mIkeSession).setNetwork(TEST_UNDERLYING_NETWORK_RECORD_2.network); + } + + @Test + public void testSameNetworkDoesNotTriggerMigration() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testCreatedTransformsAreApplied() throws Exception { + for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { + getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction); + mTestLooper.dispatchAll(); + + verify(mIpSecSvc) + .applyTunnelModeTransform( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); + } + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testChildSessionClosedTriggersDisconnect() throws Exception { + getChildSessionCallback().onClosed(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testIkeSessionClosedTriggersDisconnect() throws Exception { + getIkeSessionCallback().onClosed(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + } + + // TODO: Add tests for childOpened() when ChildSessionConfiguration can be mocked or created +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index d741e5cf4b..f4ac86d736 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,20 +16,35 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import android.annotation.NonNull; import android.content.Context; +import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.net.vcn.VcnTransportInfo; +import android.net.wifi.WifiInfo; import android.os.ParcelUuid; +import android.os.Process; import android.os.test.TestLooper; import android.telephony.SubscriptionInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; + import org.junit.Test; import org.junit.runner.RunWith; @@ -42,6 +57,7 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionTest { + private static final int TEST_UID = Process.myUid(); private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -61,22 +77,59 @@ public class VcnGatewayConnectionTest { @NonNull private final TestLooper mTestLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final VcnGatewayConnection.Dependencies mDeps; + @NonNull private final WifiInfo mWifiInfo; public VcnGatewayConnectionTest() { mContext = mock(Context.class); mTestLooper = new TestLooper(); mVcnNetworkProvider = mock(VcnNetworkProvider.class); mDeps = mock(VcnGatewayConnection.Dependencies.class); + mWifiInfo = mock(WifiInfo.class); + } + + private void verifyBuildNetworkCapabilitiesCommon(int transportType) { + final NetworkCapabilities underlyingCaps = new NetworkCapabilities(); + underlyingCaps.addTransportType(transportType); + underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED); + underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING); + + if (transportType == TRANSPORT_WIFI) { + underlyingCaps.setTransportInfo(mWifiInfo); + underlyingCaps.setOwnerUid(TEST_UID); + } else if (transportType == TRANSPORT_CELLULAR) { + underlyingCaps.setAdministratorUids(new int[] {TEST_UID}); + underlyingCaps.setNetworkSpecifier( + new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); + } + + UnderlyingNetworkRecord record = + new UnderlyingNetworkRecord( + new Network(0), underlyingCaps, new LinkProperties(), false); + final NetworkCapabilities vcnCaps = + VcnGatewayConnection.buildNetworkCapabilities( + VcnGatewayConnectionConfigTest.buildTestConfig(), record); + + assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); + assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); + + final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo(); + if (transportType == TRANSPORT_WIFI) { + assertEquals(mWifiInfo, info.getWifiInfo()); + } else if (transportType == TRANSPORT_CELLULAR) { + assertEquals(TEST_SUBSCRIPTION_ID_1, info.getSubId()); + } } @Test - public void testBuildNetworkCapabilities() throws Exception { - final NetworkCapabilities caps = - VcnGatewayConnection.buildNetworkCapabilities( - VcnGatewayConnectionConfigTest.buildTestConfig()); + public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception { + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI); + } - for (int exposedCapability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { - assertTrue(caps.hasCapability(exposedCapability)); - } + @Test + public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception { + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 4d92fb9c42..873078036a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -27,7 +27,9 @@ import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.Context; +import android.net.IpSecConfig; import android.net.IpSecManager; +import android.net.IpSecTransform; import android.net.IpSecTunnelInterfaceResponse; import android.net.LinkProperties; import android.net.Network; @@ -48,7 +50,10 @@ import java.util.UUID; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); - protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1; + protected static final int TEST_IPSEC_SPI_VALUE = 0x1234; + protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1; + protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2; + protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( @@ -112,6 +117,10 @@ public class VcnGatewayConnectionTestBase { mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); } + protected IpSecTransform makeDummyIpSecTransform() throws Exception { + return new IpSecTransform(mContext, new IpSecConfig()); + } + protected IkeSessionCallback getIkeSessionCallback() { ArgumentCaptor captor = ArgumentCaptor.forClass(IkeSessionCallback.class); From 834b60e367ae5c25d89cc21bd331edce43ffb786 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 20 Jan 2021 15:37:41 -0800 Subject: [PATCH 0044/1057] Notify UnderlyingNetworkTracker for Subscription changes. This CL updates VcnManagementService to notify active VCNs when it is notified of subscription changes by TelephonySubscriptionTracker. These subscription changes are passed down to each VCN's UnderlyingNetworkTracker, which determines whether it needs to register or unregister bringup NetworkRequests based on subIds within that VCN's Subscription Group. Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: I15bc9aaf3d5f97046d0ce9fcf1e12c9b1e0e1446 --- .../android/server/VcnManagementService.java | 11 ++- .../server/vcn/UnderlyingNetworkTracker.java | 90 +++++++++++-------- .../src/com/android/server/vcn/Vcn.java | 44 ++++++++- .../server/vcn/VcnGatewayConnection.java | 55 +++++++++++- .../server/VcnManagementServiceTest.java | 15 +++- .../vcn/UnderlyingNetworkTrackerTest.java | 24 ++--- ...atewayConnectionDisconnectedStateTest.java | 3 +- .../vcn/VcnGatewayConnectionTestBase.java | 13 ++- 8 files changed, 187 insertions(+), 68 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 6a72010738..514b26f90f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -290,8 +290,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { public Vcn newVcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, - @NonNull VcnConfig config) { - return new Vcn(vcnContext, subscriptionGroup, config); + @NonNull VcnConfig config, + @NonNull TelephonySubscriptionSnapshot snapshot) { + return new Vcn(vcnContext, subscriptionGroup, config, snapshot); } /** Gets the subId indicated by the given {@link WifiInfo}. */ @@ -382,6 +383,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // delay) for (Entry entry : mVcns.entrySet()) { final VcnConfig config = mConfigs.get(entry.getKey()); + if (config == null || !snapshot.packageHasPermissionsForSubscriptionGroup( entry.getKey(), config.getProvisioningPackageName())) { @@ -399,6 +401,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + } else { + // If this VCN's status has not changed, update it with the new snapshot + entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); } } } @@ -412,7 +417,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. - final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config); + final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot); mVcns.put(subscriptionGroup, newInstance); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index fd12c2d2eb..1de4bf794a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -28,16 +28,15 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.os.ParcelUuid; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -59,27 +58,29 @@ public class UnderlyingNetworkTracker { @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; - @NonNull private final SubscriptionManager mSubscriptionManager; - @NonNull private final SparseArray mCellBringupCallbacks = new SparseArray<>(); + @NonNull private final Map mCellBringupCallbacks = new ArrayMap<>(); @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback(); @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); - @NonNull private final Set mSubIds = new ArraySet<>(); - @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; + @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; + private boolean mIsRunning = true; + @Nullable private UnderlyingNetworkRecord mCurrentRecord; @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; public UnderlyingNetworkTracker( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb) { this( vcnContext, subscriptionGroup, + snapshot, requiredUnderlyingNetworkCapabilities, cb, new Dependencies()); @@ -88,11 +89,13 @@ public class UnderlyingNetworkTracker { private UnderlyingNetworkTracker( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); mRequiredUnderlyingNetworkCapabilities = Objects.requireNonNull( requiredUnderlyingNetworkCapabilities, @@ -103,7 +106,6 @@ public class UnderlyingNetworkTracker { mHandler = new Handler(mVcnContext.getLooper()); mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); - mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class); registerNetworkRequests(); } @@ -149,34 +151,47 @@ public class UnderlyingNetworkTracker { private void updateSubIdsAndCellularRequests() { mVcnContext.ensureRunningOnLooperThread(); - Set prevSubIds = new ArraySet<>(mSubIds); - mSubIds.clear(); - - // Ensure NetworkRequests filed for all current subIds in mSubscriptionGroup - // STOPSHIP: b/177364490 use TelephonySubscriptionSnapshot to avoid querying Telephony - List subInfos = - mSubscriptionManager.getSubscriptionsInGroup(mSubscriptionGroup); - - for (SubscriptionInfo subInfo : subInfos) { - final int subId = subInfo.getSubscriptionId(); - mSubIds.add(subId); - - if (!mCellBringupCallbacks.contains(subId)) { - final NetworkBringupCallback cb = new NetworkBringupCallback(); - mCellBringupCallbacks.put(subId, cb); - - mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), mHandler, cb); - } + // Don't bother re-filing NetworkRequests if this Tracker has been torn down. + if (!mIsRunning) { + return; } - // unregister all NetworkCallbacks for outdated subIds - for (final int subId : prevSubIds) { - if (!mSubIds.contains(subId)) { - final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId); - mConnectivityManager.unregisterNetworkCallback(cb); - } + final Set subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); + + // new subIds to track = (updated list of subIds) - (currently tracked subIds) + final Set subIdsToRegister = new ArraySet<>(subIdsInSubGroup); + subIdsToRegister.removeAll(mCellBringupCallbacks.keySet()); + + // subIds to stop tracking = (currently tracked subIds) - (updated list of subIds) + final Set subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet()); + subIdsToUnregister.removeAll(subIdsInSubGroup); + + for (final int subId : subIdsToRegister) { + final NetworkBringupCallback cb = new NetworkBringupCallback(); + mCellBringupCallbacks.put(subId, cb); + + mConnectivityManager.requestBackgroundNetwork( + getCellNetworkRequestForSubId(subId), mHandler, cb); } + + for (final int subId : subIdsToUnregister) { + final NetworkCallback cb = mCellBringupCallbacks.remove(subId); + mConnectivityManager.unregisterNetworkCallback(cb); + } + } + + /** + * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot. + * + *

    Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to + * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered + * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change. + */ + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + Objects.requireNonNull(snapshot, "Missing snapshot"); + + mLastSnapshot = snapshot; + updateSubIdsAndCellularRequests(); } /** Tears down this Tracker, and releases all underlying network requests. */ @@ -186,11 +201,12 @@ public class UnderlyingNetworkTracker { mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback); mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback); - for (final int subId : mSubIds) { - final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId); + for (final NetworkCallback cb : mCellBringupCallbacks.values()) { mConnectivityManager.unregisterNetworkCallback(cb); } - mSubIds.clear(); + mCellBringupCallbacks.clear(); + + mIsRunning = false; } /** Returns whether the currently selected Network matches the given network. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index fd19322cec..a586d072ef 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -27,6 +27,8 @@ import android.os.Message; import android.os.ParcelUuid; import android.util.Slog; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; + import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -63,6 +65,15 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_NETWORK_REQUESTED = MSG_EVENT_BASE + 1; + /** + * The TelephonySubscriptionSnapshot tracked by VcnManagementService has changed. + * + *

    This updated snapshot should be cached locally and passed to all VcnGatewayConnections. + * + * @param obj TelephonySubscriptionSnapshot + */ + private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; @@ -76,20 +87,23 @@ public class Vcn extends Handler { new HashMap<>(); @NonNull private VcnConfig mConfig; + @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; private boolean mIsRunning = true; public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, - @NonNull VcnConfig config) { - this(vcnContext, subscriptionGroup, config, new Dependencies()); + @NonNull VcnConfig config, + @NonNull TelephonySubscriptionSnapshot snapshot) { + this(vcnContext, subscriptionGroup, config, snapshot, new Dependencies()); } private Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, + @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull Dependencies deps) { super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; @@ -98,6 +112,7 @@ public class Vcn extends Handler { mRequestListener = new VcnNetworkRequestListener(); mConfig = Objects.requireNonNull(config, "Missing config"); + mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); @@ -110,6 +125,13 @@ public class Vcn extends Handler { sendMessage(obtainMessage(MSG_EVENT_CONFIG_UPDATED, config)); } + /** Asynchronously updates the Subscription snapshot for this VCN. */ + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + Objects.requireNonNull(snapshot, "Missing snapshot"); + + sendMessage(obtainMessage(MSG_EVENT_SUBSCRIPTIONS_CHANGED, snapshot)); + } + /** Asynchronously tears down this Vcn instance, including VcnGatewayConnection(s) */ public void teardownAsynchronously() { sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); @@ -137,6 +159,9 @@ public class Vcn extends Handler { case MSG_EVENT_NETWORK_REQUESTED: handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2); break; + case MSG_EVENT_SUBSCRIPTIONS_CHANGED: + handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; @@ -193,12 +218,25 @@ public class Vcn extends Handler { final VcnGatewayConnection vcnGatewayConnection = new VcnGatewayConnection( - mVcnContext, mSubscriptionGroup, gatewayConnectionConfig); + mVcnContext, + mSubscriptionGroup, + mLastSnapshot, + gatewayConnectionConfig); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } } + private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { + mLastSnapshot = snapshot; + + if (mIsRunning) { + for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { + gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); + } + } + } + private boolean requestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index db372270fe..853bb4324f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -61,10 +61,12 @@ import android.os.ParcelUuid; import android.util.ArraySet; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; @@ -371,6 +373,16 @@ public class VcnGatewayConnection extends StateMachine { */ private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8; + /** + * Sent when this VcnGatewayConnection is notified of a change in TelephonySubscriptions. + * + *

    Relevant in all states. + * + * @param arg1 The "all" token; this signal is always honored. + */ + // TODO(b/178426520): implement handling of this event + private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9; + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -391,6 +403,11 @@ public class VcnGatewayConnection extends StateMachine { @NonNull final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); + @NonNull private final Object mLock = new Object(); + + @GuardedBy("mLock") + @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @@ -469,14 +486,16 @@ public class VcnGatewayConnection extends StateMachine { public VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig) { - this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies()); + this(vcnContext, subscriptionGroup, snapshot, connectionConfig, new Dependencies()); } @VisibleForTesting(visibility = Visibility.PRIVATE) VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull Dependencies deps) { super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); @@ -485,12 +504,17 @@ public class VcnGatewayConnection extends StateMachine { mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); mDeps = Objects.requireNonNull(deps, "Missing deps"); + synchronized (mLock) { + mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); + } + mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback(); mUnderlyingNetworkTracker = mDeps.newUnderlyingNetworkTracker( mVcnContext, subscriptionGroup, + mLastSnapshot, mConnectionConfig.getAllUnderlyingCapabilities(), mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); @@ -545,6 +569,25 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkTracker.teardown(); } + /** + * Notify this Gateway that subscriptions have changed. + * + *

    This snapshot should be used to update any keepalive requests necessary for potential + * underlying Networks in this Gateway's subscription group. + */ + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + Objects.requireNonNull(snapshot, "Missing snapshot"); + + // Vcn is the only user of this method and runs on the same Thread, but lock around + // mLastSnapshot to be technically correct. + synchronized (mLock) { + mLastSnapshot = snapshot; + mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot); + } + + sendMessage(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); + } + private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override public void onSelectedUnderlyingNetworkChanged( @@ -682,7 +725,8 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_TRANSFORM_CREATED: // Fallthrough case EVENT_SETUP_COMPLETED: // Fallthrough case EVENT_DISCONNECT_REQUESTED: // Fallthrough - case EVENT_TEARDOWN_TIMEOUT_EXPIRED: + case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough + case EVENT_SUBSCRIPTIONS_CHANGED: logUnexpectedEvent(msg.what); break; default: @@ -1384,10 +1428,15 @@ public class VcnGatewayConnection extends StateMachine { public UnderlyingNetworkTracker newUnderlyingNetworkTracker( VcnContext vcnContext, ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, Set requiredUnderlyingNetworkCapabilities, UnderlyingNetworkTrackerCallback callback) { return new UnderlyingNetworkTracker( - vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback); + vcnContext, + subscriptionGroup, + snapshot, + requiredUnderlyingNetworkCapabilities, + callback); } /** Builds a new IkeSession. */ diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index e7d334ebd4..e0517ce766 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -184,7 +184,7 @@ public class VcnManagementServiceTest { doAnswer((invocation) -> { // Mock-within a doAnswer is safe, because it doesn't actually run nested. return mock(Vcn.class); - }).when(mMockDeps).newVcn(any(), any(), any()); + }).when(mMockDeps).newVcn(any(), any(), any(), any()); final PersistableBundle bundle = PersistableBundleUtils.fromMap( @@ -304,8 +304,10 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); - verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG)); + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + verify(mMockDeps) + .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot)); } @Test @@ -473,7 +475,12 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); // Verify Vcn is started - verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG)); + verify(mMockDeps) + .newVcn( + eq(mVcnContext), + eq(TEST_UUID_2), + eq(TEST_VCN_CONFIG), + eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT)); // Verify Vcn is updated if it was previously started mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 48e068d141..f5c171c76c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -42,8 +42,9 @@ import android.net.TelephonyNetworkSpecifier; import android.os.ParcelUuid; import android.os.test.TestLooper; import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; +import android.util.ArraySet; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; @@ -58,7 +59,7 @@ import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Collections; -import java.util.List; +import java.util.Set; import java.util.UUID; public class UnderlyingNetworkTrackerTest { @@ -90,7 +91,7 @@ public class UnderlyingNetworkTrackerTest { @Mock private Context mContext; @Mock private VcnNetworkProvider mVcnNetworkProvider; @Mock private ConnectivityManager mConnectivityManager; - @Mock private SubscriptionManager mSubscriptionManager; + @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; @Mock private Network mNetwork; @@ -113,23 +114,16 @@ public class UnderlyingNetworkTrackerTest { mConnectivityManager, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); - setupSystemService( - mContext, - mSubscriptionManager, - Context.TELEPHONY_SUBSCRIPTION_SERVICE, - SubscriptionManager.class); - List initialSubInfos = - Arrays.asList( - getSubscriptionInfoForSubId(INITIAL_SUB_ID_1), - getSubscriptionInfoForSubId(INITIAL_SUB_ID_2)); - when(mSubscriptionManager.getSubscriptionsInGroup(eq(SUB_GROUP))) - .thenReturn(initialSubInfos); + Set initialSubIds = + new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2)); + when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(initialSubIds); mUnderlyingNetworkTracker = new UnderlyingNetworkTracker( mVcnContext, SUB_GROUP, + mSubscriptionSnapshot, Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); } @@ -170,7 +164,7 @@ public class UnderlyingNetworkTrackerTest { any(), any(RouteSelectionCallback.class)); - verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP)); + verify(mSubscriptionSnapshot).getAllSubIdsInGroup(eq(SUB_GROUP)); } private NetworkRequest getWifiRequest() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 4ecd215031..fbaae6f534 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -44,7 +44,8 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect @Test public void testEnterWhileNotRunningTriggersQuit() throws Exception { final VcnGatewayConnection vgc = - new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + new VcnGatewayConnection( + mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps); vgc.setIsRunning(false); vgc.transitionTo(vgc.mDisconnectedState); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 873078036a..df1341cce2 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -42,10 +42,12 @@ import android.os.ParcelUuid; import android.os.test.TestLooper; import com.android.server.IpSecService; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import org.junit.Before; import org.mockito.ArgumentCaptor; +import java.util.Collections; import java.util.UUID; public class VcnGatewayConnectionTestBase { @@ -54,6 +56,7 @@ public class VcnGatewayConnectionTestBase { protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1; protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2; protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3; + protected static final int TEST_SUB_ID = 5; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( @@ -68,6 +71,10 @@ public class VcnGatewayConnectionTestBase { new LinkProperties(), false /* blocked */); + protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = + new TelephonySubscriptionSnapshot( + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); + @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; @@ -99,7 +106,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any(), any()); + .newUnderlyingNetworkTracker(any(), any(), any(), any(), any()); } @Before @@ -114,7 +121,9 @@ public class VcnGatewayConnectionTestBase { mMockIkeSession = mock(VcnIkeSession.class); doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any()); - mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + mGatewayConnection = + new VcnGatewayConnection( + mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps); } protected IpSecTransform makeDummyIpSecTransform() throws Exception { From e6006cd68e315e5c7de05ad1452c9b80108d8636 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 22 Jan 2021 09:59:07 -0800 Subject: [PATCH 0045/1057] Unit test TelephonySubscriptionSnapshot changes for VCNs. This CL adds unit testing for TelephonySubscriptionSnapshot updates in UnderlyingNetworkTracker, Vcn, and VcnManagementService. Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: I244744194a1360c7c7dee062a302e04f9b5efc32 --- .../src/com/android/server/vcn/Vcn.java | 30 +++- .../server/vcn/VcnNetworkProvider.java | 17 ++- .../server/VcnManagementServiceTest.java | 12 ++ .../vcn/UnderlyingNetworkTrackerTest.java | 54 ++++++-- .../server/vcn/VcnGatewayConnectionTest.java | 34 +++-- .../java/com/android/server/vcn/VcnTest.java | 129 ++++++++++++++++++ 6 files changed, 241 insertions(+), 35 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index a586d072ef..a82f239948 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -27,11 +27,16 @@ import android.os.Message; import android.os.ParcelUuid; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; /** * Represents an single instance of a VCN. @@ -99,7 +104,8 @@ public class Vcn extends Handler { this(vcnContext, subscriptionGroup, config, snapshot, new Dependencies()); } - private Vcn( + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @@ -137,6 +143,12 @@ public class Vcn extends Handler { sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); } + /** Get current Gateways for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Set getVcnGatewayConnections() { + return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values())); + } + private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { @@ -217,7 +229,7 @@ public class Vcn extends Handler { "Bringing up new VcnGatewayConnection for request " + request.requestId); final VcnGatewayConnection vcnGatewayConnection = - new VcnGatewayConnection( + mDeps.newVcnGatewayConnection( mVcnContext, mSubscriptionGroup, mLastSnapshot, @@ -259,5 +271,17 @@ public class Vcn extends Handler { return 52; } - private static class Dependencies {} + /** External dependencies used by Vcn, for injection in tests */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Builds a new VcnGatewayConnection */ + public VcnGatewayConnection newVcnGatewayConnection( + VcnContext vcnContext, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + VcnGatewayConnectionConfig connectionConfig) { + return new VcnGatewayConnection( + vcnContext, subscriptionGroup, snapshot, connectionConfig); + } + } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index b9babae4c6..fe4ea30361 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -25,6 +25,9 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + import java.util.Objects; import java.util.Set; @@ -52,8 +55,13 @@ public class VcnNetworkProvider extends NetworkProvider { super(context, looper, VcnNetworkProvider.class.getSimpleName()); } - // Package-private - void registerListener(@NonNull NetworkRequestListener listener) { + /** + * Registers a NetworkRequestListener with this NetworkProvider. + * + *

    Upon registering, the provided listener will receive all cached requests. + */ + @VisibleForTesting(visibility = Visibility.PACKAGE) + public void registerListener(@NonNull NetworkRequestListener listener) { mListeners.add(listener); // Send listener all cached requests @@ -62,8 +70,9 @@ public class VcnNetworkProvider extends NetworkProvider { } } - // Package-private - void unregisterListener(@NonNull NetworkRequestListener listener) { + /** Unregisters the specified listener from receiving future NetworkRequests. */ + @VisibleForTesting(visibility = Visibility.PACKAGE) + public void unregisterListener(@NonNull NetworkRequestListener listener) { mListeners.remove(listener); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index e0517ce766..4ad8ea7d0b 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -598,4 +598,16 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties()); } + + @Test + public void testSubscriptionSnapshotUpdateNotifiesVcn() { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); + final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2); + + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + + verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot)); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index f5c171c76c..1d459a3475 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -66,6 +66,12 @@ public class UnderlyingNetworkTrackerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int INITIAL_SUB_ID_1 = 1; private static final int INITIAL_SUB_ID_2 = 2; + private static final int UPDATED_SUB_ID = 3; + + private static final Set INITIAL_SUB_IDS = + new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2)); + private static final Set UPDATED_SUB_IDS = + new ArraySet<>(Arrays.asList(UPDATED_SUB_ID)); private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES = new NetworkCapabilities.Builder() @@ -115,9 +121,7 @@ public class UnderlyingNetworkTrackerTest { Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); - Set initialSubIds = - new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2)); - when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(initialSubIds); + when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); mUnderlyingNetworkTracker = new UnderlyingNetworkTracker( @@ -148,23 +152,45 @@ public class UnderlyingNetworkTrackerTest { eq(getWifiRequest()), any(), any(NetworkBringupCallback.class)); - verify(mConnectivityManager) - .requestBackgroundNetwork( - eq(getCellRequestForSubId(INITIAL_SUB_ID_1)), - any(), - any(NetworkBringupCallback.class)); - verify(mConnectivityManager) - .requestBackgroundNetwork( - eq(getCellRequestForSubId(INITIAL_SUB_ID_2)), - any(), - any(NetworkBringupCallback.class)); + verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); + verify(mConnectivityManager) .requestBackgroundNetwork( eq(getRouteSelectionRequest()), any(), any(RouteSelectionCallback.class)); + } - verify(mSubscriptionSnapshot).getAllSubIdsInGroup(eq(SUB_GROUP)); + private void verifyBackgroundCellRequests( + TelephonySubscriptionSnapshot snapshot, + ParcelUuid subGroup, + Set expectedSubIds) { + verify(snapshot).getAllSubIdsInGroup(eq(subGroup)); + + for (final int subId : expectedSubIds) { + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getCellRequestForSubId(subId)), + any(), + any(NetworkBringupCallback.class)); + } + } + + @Test + public void testUpdateSubscriptionSnapshot() { + // Verify initial cell background requests filed + verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); + + TelephonySubscriptionSnapshot subscriptionUpdate = + mock(TelephonySubscriptionSnapshot.class); + when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS); + + mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); + + // verify that initially-filed bringup requests are unregistered + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size())) + .unregisterNetworkCallback(any(NetworkBringupCallback.class)); + verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS); } private NetworkRequest getWifiRequest() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index f4ac86d736..bc6bee28d1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -24,10 +24,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; -import android.annotation.NonNull; -import android.content.Context; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -37,14 +37,15 @@ import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.os.ParcelUuid; import android.os.Process; -import android.os.test.TestLooper; import android.telephony.SubscriptionInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,8 +57,9 @@ import java.util.UUID; /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @SmallTest -public class VcnGatewayConnectionTest { +public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid(); + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -73,17 +75,12 @@ public class VcnGatewayConnectionTest { TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); } - @NonNull private final Context mContext; - @NonNull private final TestLooper mTestLooper; - @NonNull private final VcnNetworkProvider mVcnNetworkProvider; - @NonNull private final VcnGatewayConnection.Dependencies mDeps; - @NonNull private final WifiInfo mWifiInfo; + private WifiInfo mWifiInfo; + + @Before + public void setUp() throws Exception { + super.setUp(); - public VcnGatewayConnectionTest() { - mContext = mock(Context.class); - mTestLooper = new TestLooper(); - mVcnNetworkProvider = mock(VcnNetworkProvider.class); - mDeps = mock(VcnGatewayConnection.Dependencies.class); mWifiInfo = mock(WifiInfo.class); } @@ -132,4 +129,13 @@ public class VcnGatewayConnectionTest { public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception { verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR); } + + @Test + public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot); + + verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot)); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java new file mode 100644 index 0000000000..0c1df763a0 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -0,0 +1,129 @@ +/* + * 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.server.vcn; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.NetworkRequest; +import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.os.ParcelUuid; +import android.os.test.TestLooper; + +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.util.Set; +import java.util.UUID; + +public class VcnTest { + private static final String PKG_NAME = VcnTest.class.getPackage().getName(); + private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + private static final int NETWORK_SCORE = 0; + private static final int PROVIDER_ID = 5; + + private Context mContext; + private VcnContext mVcnContext; + private TelephonySubscriptionSnapshot mSubscriptionSnapshot; + private VcnNetworkProvider mVcnNetworkProvider; + private Vcn.Dependencies mDeps; + + private TestLooper mTestLooper; + private VcnConfig mConfig; + private Vcn mVcn; + + @Before + public void setUp() { + mContext = mock(Context.class); + mVcnContext = mock(VcnContext.class); + mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); + mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mDeps = mock(Vcn.Dependencies.class); + + mTestLooper = new TestLooper(); + + doReturn(PKG_NAME).when(mContext).getOpPackageName(); + doReturn(mContext).when(mVcnContext).getContext(); + doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); + doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + + // Setup VcnGatewayConnection instance generation + doAnswer((invocation) -> { + // Mock-within a doAnswer is safe, because it doesn't actually run nested. + return mock(VcnGatewayConnection.class); + }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any()); + + mConfig = + new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig( + VcnGatewayConnectionConfigTest.buildTestConfig()) + .build(); + + mVcn = new Vcn(mVcnContext, TEST_SUB_GROUP, mConfig, mSubscriptionSnapshot, mDeps); + } + + private NetworkRequestListener verifyAndGetRequestListener() { + ArgumentCaptor mNetworkRequestListenerCaptor = + ArgumentCaptor.forClass(NetworkRequestListener.class); + verify(mVcnNetworkProvider).registerListener(mNetworkRequestListenerCaptor.capture()); + + return mNetworkRequestListenerCaptor.getValue(); + } + + private NetworkRequest getNetworkRequestWithCapabilities(int[] networkCapabilities) { + final NetworkRequest.Builder builder = new NetworkRequest.Builder(); + for (final int netCapability : networkCapabilities) { + builder.addCapability(netCapability); + } + return builder.build(); + } + + @Test + public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + + requestListener.onNetworkRequested( + getNetworkRequestWithCapabilities(VcnGatewayConnectionConfigTest.EXPOSED_CAPS), + NETWORK_SCORE, + PROVIDER_ID); + mTestLooper.dispatchAll(); + + final Set gatewayConnections = mVcn.getVcnGatewayConnections(); + assertFalse(gatewayConnections.isEmpty()); + + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + for (final VcnGatewayConnection gateway : gatewayConnections) { + verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot)); + } + } +} From 39b822010888218786d883d855c3ff3157aa1ea6 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 27 Jan 2021 12:27:33 -0800 Subject: [PATCH 0046/1057] Notify PolicyListeners to refresh their policy on VCN changes. This CL updates VcnManagementService to notify all registered VcnUnderlyingNetworkPolicyListeners to refresh their UnderlyingNetworkPolicy when any VCN is added or removed. Bug: 175914059 Test: atest FrameworksVcnTests Change-Id: Ie87f4aa3401c6c4ba9f932130a1d475e35f59d4e --- .../android/server/VcnManagementService.java | 31 ++++++++++++++++--- .../server/VcnManagementServiceTest.java | 24 ++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 514b26f90f..916bec27af 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -397,7 +397,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // correct instance is torn down. This could happen as a result of a // Carrier App manually removing/adding a VcnConfig. if (mVcns.get(uuidToTeardown) == instanceToTeardown) { - mVcns.remove(uuidToTeardown).teardownAsynchronously(); + stopVcnLocked(uuidToTeardown); } } }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -410,6 +410,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + @GuardedBy("mLock") + private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { + final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown); + if (vcnToTeardown == null) { + return; + } + + vcnToTeardown.teardownAsynchronously(); + + // Now that the VCN is removed, notify all registered listeners to refresh their + // UnderlyingNetworkPolicy. + notifyAllPolicyListenersLocked(); + } + + @GuardedBy("mLock") + private void notifyAllPolicyListenersLocked() { + for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) { + Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged()); + } + } + @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); @@ -419,6 +440,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot); mVcns.put(subscriptionGroup, newInstance); + + // Now that a new VCN has started, notify all registered listeners to refresh their + // UnderlyingNetworkPolicy. + notifyAllPolicyListenersLocked(); } @GuardedBy("mLock") @@ -481,9 +506,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { mConfigs.remove(subscriptionGroup); - if (mVcns.containsKey(subscriptionGroup)) { - mVcns.remove(subscriptionGroup).teardownAsynchronously(); - } + stopVcnLocked(subscriptionGroup); writeConfigsToDiskLocked(); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4ad8ea7d0b..de51b2bd73 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -314,6 +314,7 @@ public class VcnManagementServiceTest { public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception { final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); @@ -321,6 +322,7 @@ public class VcnManagementServiceTest { mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); verify(vcn).teardownAsynchronously(); + verify(mMockPolicyListener).onPolicyChanged(); } @Test @@ -391,6 +393,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); fail("Expected security exception for non system user"); } catch (SecurityException expected) { + verify(mMockPolicyListener, never()).onPolicyChanged(); } } @@ -402,6 +405,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { + verify(mMockPolicyListener, never()).onPolicyChanged(); } } @@ -411,6 +415,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage"); fail("Expected exception due to mismatched packages in config and method call"); } catch (IllegalArgumentException expected) { + verify(mMockPolicyListener, never()).onPolicyChanged(); } } @@ -610,4 +615,23 @@ public class VcnManagementServiceTest { verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot)); } + + @Test + public void testAddNewVcnUpdatesPolicyListener() throws Exception { + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockPolicyListener).onPolicyChanged(); + } + + @Test + public void testRemoveVcnUpdatesPolicyListener() throws Exception { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + + verify(mMockPolicyListener).onPolicyChanged(); + } } From 0183e420e9a51b8767eac5bcf138aa91692c3d33 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 1 Feb 2021 22:46:32 -0800 Subject: [PATCH 0047/1057] Fix field order for UnderlyingNetworkTracker. Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: Ie1671925ab0427d47020673cca7c889bff8b6a8a --- .../src/com/android/server/vcn/UnderlyingNetworkTracker.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 1de4bf794a..b6ddd93af3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -54,6 +54,7 @@ public class UnderlyingNetworkTracker { @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; + @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @@ -63,8 +64,6 @@ public class UnderlyingNetworkTracker { @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback(); @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); - @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; - @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; private boolean mIsRunning = true; From 3af8ca1b62dc48102a88df657f05aeb38494a88d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 1 Feb 2021 22:54:06 -0800 Subject: [PATCH 0048/1057] Fix test method naming in VcnManagementServiceTest. Bug: 175914059 Test: atest FrameworksVcnTests Change-Id: I03be15d63adfccc357000ee670e373d0359a3c06 --- .../com/android/server/VcnManagementServiceTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index de51b2bd73..e32e1e831f 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -532,7 +532,7 @@ public class VcnManagementServiceTest { Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup)); } - private void verifyMergedNetworkCapabilities( + private void verifyMergedNetworkCapabilitiesIsVcnManaged( NetworkCapabilities mergedCapabilities, @Transport int transportType) { assertTrue(mergedCapabilities.hasTransport(transportType)); assertFalse( @@ -541,7 +541,7 @@ public class VcnManagementServiceTest { } @Test - public void testGetUnderlyingNetworkPolicyTransportCell() throws Exception { + public void testGetUnderlyingNetworkPolicyCellular() throws Exception { setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); NetworkCapabilities nc = @@ -554,12 +554,12 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); assertFalse(policy.isTeardownRequested()); - verifyMergedNetworkCapabilities( + verifyMergedNetworkCapabilitiesIsVcnManaged( policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR); } @Test - public void testGetUnderlyingNetworkPolicyTransportWifi() throws Exception { + public void testGetUnderlyingNetworkPolicyWifi() throws Exception { setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); WifiInfo wifiInfo = mock(WifiInfo.class); @@ -575,7 +575,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); assertFalse(policy.isTeardownRequested()); - verifyMergedNetworkCapabilities( + verifyMergedNetworkCapabilitiesIsVcnManaged( policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI); } From e25e6aca5e4813c660662c6a2c38d93b1bb94bcd Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 1 Feb 2021 11:52:40 -0800 Subject: [PATCH 0049/1057] Support Safemode for VCNs. This CL updates VcnManagementService to support Safemode for VCN instances. Specifically, VcnGatewayConnections will notify their Vcn instance when they enter Safemode. Vcn instances will in-turn notify VcnManagementService, which notifies all registered UnderlyingNetworkPolicyListeners to update their policies. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: I3336c150e9406b3eb2330d2e86cae2ed835730bb --- .../android/server/VcnManagementService.java | 46 ++++++++-- .../src/com/android/server/vcn/Vcn.java | 85 ++++++++++++++++-- .../server/vcn/VcnGatewayConnection.java | 16 +++- .../vcn/VcnGatewayConnectionConfigTest.java | 7 +- .../server/VcnManagementServiceTest.java | 32 ++++++- ...atewayConnectionDisconnectedStateTest.java | 7 +- .../vcn/VcnGatewayConnectionTestBase.java | 10 ++- .../java/com/android/server/vcn/VcnTest.java | 90 +++++++++++++++---- 8 files changed, 252 insertions(+), 41 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 916bec27af..4dce59f23a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -66,6 +66,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** @@ -291,8 +292,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, - @NonNull TelephonySubscriptionSnapshot snapshot) { - return new Vcn(vcnContext, subscriptionGroup, config, snapshot); + @NonNull TelephonySubscriptionSnapshot snapshot, + @NonNull VcnSafemodeCallback safemodeCallback) { + return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safemodeCallback); } /** Gets the subId indicated by the given {@link WifiInfo}. */ @@ -438,7 +440,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. - final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot); + final VcnSafemodeCallbackImpl safemodeCallback = + new VcnSafemodeCallbackImpl(subscriptionGroup); + + final Vcn newInstance = + mDeps.newVcn( + mVcnContext, subscriptionGroup, config, mLastSnapshot, safemodeCallback); mVcns.put(subscriptionGroup, newInstance); // Now that a new VCN has started, notify all registered listeners to refresh their @@ -536,7 +543,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } - /** Get current configuration list for testing purposes */ + /** Get current VCNs for testing purposes */ @VisibleForTesting(visibility = Visibility.PRIVATE) public Map getAllVcns() { synchronized (mLock) { @@ -638,8 +645,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); - // TODO(b/178140910): only mark the Network as VCN-managed if not in safe mode - if (mVcns.containsKey(subGroup)) { + Vcn vcn = mVcns.get(subGroup); + if (vcn != null && vcn.isActive()) { isVcnManagedNetwork = true; } } @@ -651,4 +658,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); } + + /** Callback for signalling when a Vcn has entered Safemode. */ + public interface VcnSafemodeCallback { + /** Called by a Vcn to signal that it has entered Safemode. */ + void onEnteredSafemode(); + } + + /** VcnSafemodeCallback is used by Vcns to notify VcnManagementService on entering Safemode. */ + private class VcnSafemodeCallbackImpl implements VcnSafemodeCallback { + @NonNull private final ParcelUuid mSubGroup; + + private VcnSafemodeCallbackImpl(@NonNull final ParcelUuid subGroup) { + mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup"); + } + + @Override + public void onEnteredSafemode() { + synchronized (mLock) { + // Ignore if this subscription group doesn't exist anymore + if (!mVcns.containsKey(mSubGroup)) { + return; + } + + notifyAllPolicyListenersLocked(); + } + } + } } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index a82f239948..5ec527a7d6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -29,6 +29,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.VcnManagementService.VcnSafemodeCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.Collections; @@ -37,6 +38,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; /** * Represents an single instance of a VCN. @@ -82,10 +84,19 @@ public class Vcn extends Handler { /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; + /** + * Causes this VCN to immediately enter Safemode. + * + *

    Upon entering Safemode, the VCN will unregister its RequestListener, tear down all of its + * VcnGatewayConnections, and notify VcnManagementService that it is in Safemode. + */ + private static final int MSG_CMD_ENTER_SAFEMODE = MSG_CMD_BASE + 1; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Dependencies mDeps; @NonNull private final VcnNetworkRequestListener mRequestListener; + @NonNull private final VcnSafemodeCallback mVcnSafemodeCallback; @NonNull private final Map mVcnGatewayConnections = @@ -94,14 +105,33 @@ public class Vcn extends Handler { @NonNull private VcnConfig mConfig; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; - private boolean mIsRunning = true; + /** + * Whether this Vcn instance is active and running. + * + *

    The value will be {@code true} while running. It will be {@code false} if the VCN has been + * shut down or has entered safe mode. + * + *

    This AtomicBoolean is required in order to ensure consistency and correctness across + * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads + * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN + * Looper. + */ + // TODO(b/179429339): update when exiting safemode (when a new VcnConfig is provided) + private final AtomicBoolean mIsActive = new AtomicBoolean(true); public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, - @NonNull TelephonySubscriptionSnapshot snapshot) { - this(vcnContext, subscriptionGroup, config, snapshot, new Dependencies()); + @NonNull TelephonySubscriptionSnapshot snapshot, + @NonNull VcnSafemodeCallback vcnSafemodeCallback) { + this( + vcnContext, + subscriptionGroup, + config, + snapshot, + vcnSafemodeCallback, + new Dependencies()); } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -110,10 +140,13 @@ public class Vcn extends Handler { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, + @NonNull VcnSafemodeCallback vcnSafemodeCallback, @NonNull Dependencies deps) { super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + mVcnSafemodeCallback = + Objects.requireNonNull(vcnSafemodeCallback, "Missing vcnSafemodeCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mRequestListener = new VcnNetworkRequestListener(); @@ -143,6 +176,11 @@ public class Vcn extends Handler { sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); } + /** Synchronously checks whether this Vcn is active. */ + public boolean isActive() { + return mIsActive.get(); + } + /** Get current Gateways for testing purposes */ @VisibleForTesting(visibility = Visibility.PRIVATE) public Set getVcnGatewayConnections() { @@ -160,7 +198,7 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { - if (!mIsRunning) { + if (!isActive()) { return; } @@ -177,6 +215,9 @@ public class Vcn extends Handler { case MSG_CMD_TEARDOWN: handleTeardown(); break; + case MSG_CMD_ENTER_SAFEMODE: + handleEnterSafemode(); + break; default: Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); } @@ -198,7 +239,13 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } - mIsRunning = false; + mIsActive.set(false); + } + + private void handleEnterSafemode() { + handleTeardown(); + + mVcnSafemodeCallback.onEnteredSafemode(); } private void handleNetworkRequested( @@ -233,7 +280,8 @@ public class Vcn extends Handler { mVcnContext, mSubscriptionGroup, mLastSnapshot, - gatewayConnectionConfig); + gatewayConnectionConfig, + new VcnGatewayStatusCallbackImpl()); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } @@ -242,7 +290,7 @@ public class Vcn extends Handler { private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; - if (mIsRunning) { + if (isActive()) { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } @@ -271,6 +319,20 @@ public class Vcn extends Handler { return 52; } + /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ + @VisibleForTesting(visibility = Visibility.PACKAGE) + public interface VcnGatewayStatusCallback { + /** Called by a VcnGatewayConnection to indicate that it has entered Safemode. */ + void onEnteredSafemode(); + } + + private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { + @Override + public void onEnteredSafemode() { + sendMessage(obtainMessage(MSG_CMD_ENTER_SAFEMODE)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -279,9 +341,14 @@ public class Vcn extends Handler { VcnContext vcnContext, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - VcnGatewayConnectionConfig connectionConfig) { + VcnGatewayConnectionConfig connectionConfig, + VcnGatewayStatusCallback gatewayStatusCallback) { return new VcnGatewayConnection( - vcnContext, subscriptionGroup, snapshot, connectionConfig); + vcnContext, + subscriptionGroup, + snapshot, + connectionConfig, + gatewayStatusCallback); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 853bb4324f..bd82fcc144 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -69,6 +69,7 @@ import com.android.internal.util.StateMachine; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; +import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import java.io.IOException; import java.net.Inet4Address; @@ -412,6 +413,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; + @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull private final Dependencies mDeps; @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; @@ -487,8 +489,15 @@ public class VcnGatewayConnection extends StateMachine { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnGatewayConnectionConfig connectionConfig) { - this(vcnContext, subscriptionGroup, snapshot, connectionConfig, new Dependencies()); + @NonNull VcnGatewayConnectionConfig connectionConfig, + @NonNull VcnGatewayStatusCallback gatewayStatusCallback) { + this( + vcnContext, + subscriptionGroup, + snapshot, + connectionConfig, + gatewayStatusCallback, + new Dependencies()); } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -497,11 +506,14 @@ public class VcnGatewayConnection extends StateMachine { @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, + @NonNull VcnGatewayStatusCallback gatewayStatusCallback, @NonNull Dependencies deps) { super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); + mGatewayStatusCallback = + Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); synchronized (mLock) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 86a15912b6..3e659d0bc1 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -59,12 +59,17 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { + return buildTestConfigWithExposedCaps(EXPOSED_CAPS); + } + + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = new VcnGatewayConnectionConfig.Builder() .setRetryInterval(RETRY_INTERVALS_MS) .setMaxMtu(MAX_MTU); - for (int caps : EXPOSED_CAPS) { + for (int caps : exposedCaps) { builder.addExposedCapability(caps); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index e32e1e831f..485964487f 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -66,6 +66,7 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.VcnManagementService.VcnSafemodeCallback; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; @@ -142,6 +143,9 @@ public class VcnManagementServiceTest { private final TelephonySubscriptionTracker mSubscriptionTracker = mock(TelephonySubscriptionTracker.class); + private final ArgumentCaptor mSafemodeCallbackCaptor = + ArgumentCaptor.forClass(VcnSafemodeCallback.class); + private final VcnManagementService mVcnMgmtSvc; private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener = @@ -184,7 +188,7 @@ public class VcnManagementServiceTest { doAnswer((invocation) -> { // Mock-within a doAnswer is safe, because it doesn't actually run nested. return mock(Vcn.class); - }).when(mMockDeps).newVcn(any(), any(), any(), any()); + }).when(mMockDeps).newVcn(any(), any(), any(), any(), any()); final PersistableBundle bundle = PersistableBundleUtils.fromMap( @@ -307,7 +311,7 @@ public class VcnManagementServiceTest { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); verify(mMockDeps) - .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot)); + .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); } @Test @@ -485,7 +489,8 @@ public class VcnManagementServiceTest { eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), - eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT)); + eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT), + any()); // Verify Vcn is updated if it was previously started mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -634,4 +639,25 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + + @Test + public void testVcnSafemodeCallbackOnEnteredSafemode() throws Exception { + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + verify(mMockDeps) + .newVcn( + eq(mVcnContext), + eq(TEST_UUID_1), + eq(TEST_VCN_CONFIG), + eq(snapshot), + mSafemodeCallbackCaptor.capture()); + + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + VcnSafemodeCallback safemodeCallback = mSafemodeCallbackCaptor.getValue(); + safemodeCallback.onEnteredSafemode(); + + assertFalse(mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1).isActive()); + verify(mMockPolicyListener).onPolicyChanged(); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index fbaae6f534..8643d8a2ea 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -45,7 +45,12 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect public void testEnterWhileNotRunningTriggersQuit() throws Exception { final VcnGatewayConnection vgc = new VcnGatewayConnection( - mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps); + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + mConfig, + mGatewayStatusCallback, + mDeps); vgc.setIsRunning(false); vgc.transitionTo(vgc.mDisconnectedState); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index df1341cce2..333b5b990d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -43,6 +43,7 @@ import android.os.test.TestLooper; import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -80,6 +81,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; @NonNull protected final VcnContext mVcnContext; @NonNull protected final VcnGatewayConnectionConfig mConfig; + @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull protected final VcnGatewayConnection.Dependencies mDeps; @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @@ -94,6 +96,7 @@ public class VcnGatewayConnectionTestBase { mVcnNetworkProvider = mock(VcnNetworkProvider.class); mVcnContext = mock(VcnContext.class); mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); + mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class); mDeps = mock(VcnGatewayConnection.Dependencies.class); mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); @@ -123,7 +126,12 @@ public class VcnGatewayConnectionTestBase { mGatewayConnection = new VcnGatewayConnection( - mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps); + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + mConfig, + mGatewayStatusCallback, + mDeps); } protected IpSecTransform makeDummyIpSecTransform() throws Exception { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 0c1df763a0..66cbf84619 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -16,22 +16,27 @@ package com.android.server.vcn; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.net.NetworkRequest; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; +import com.android.server.VcnManagementService.VcnSafemodeCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; @@ -51,9 +56,13 @@ public class VcnTest { private VcnContext mVcnContext; private TelephonySubscriptionSnapshot mSubscriptionSnapshot; private VcnNetworkProvider mVcnNetworkProvider; + private VcnSafemodeCallback mVcnSafemodeCallback; private Vcn.Dependencies mDeps; + private ArgumentCaptor mGatewayStatusCallbackCaptor; + private TestLooper mTestLooper; + private VcnGatewayConnectionConfig mGatewayConnectionConfig; private VcnConfig mConfig; private Vcn mVcn; @@ -63,6 +72,7 @@ public class VcnTest { mVcnContext = mock(VcnContext.class); mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mVcnSafemodeCallback = mock(VcnSafemodeCallback.class); mDeps = mock(Vcn.Dependencies.class); mTestLooper = new TestLooper(); @@ -76,15 +86,26 @@ public class VcnTest { doAnswer((invocation) -> { // Mock-within a doAnswer is safe, because it doesn't actually run nested. return mock(VcnGatewayConnection.class); - }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any()); + }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any()); - mConfig = - new VcnConfig.Builder(mContext) - .addGatewayConnectionConfig( - VcnGatewayConnectionConfigTest.buildTestConfig()) - .build(); + mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); - mVcn = new Vcn(mVcnContext, TEST_SUB_GROUP, mConfig, mSubscriptionSnapshot, mDeps); + final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext); + for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + configBuilder.addGatewayConnectionConfig( + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability)); + } + configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig()); + mConfig = configBuilder.build(); + + mVcn = + new Vcn( + mVcnContext, + TEST_SUB_GROUP, + mConfig, + mSubscriptionSnapshot, + mVcnSafemodeCallback, + mDeps); } private NetworkRequestListener verifyAndGetRequestListener() { @@ -95,23 +116,22 @@ public class VcnTest { return mNetworkRequestListenerCaptor.getValue(); } - private NetworkRequest getNetworkRequestWithCapabilities(int[] networkCapabilities) { - final NetworkRequest.Builder builder = new NetworkRequest.Builder(); - for (final int netCapability : networkCapabilities) { - builder.addCapability(netCapability); + private void startVcnGatewayWithCapabilities( + NetworkRequestListener requestListener, int... netCapabilities) { + final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); + for (final int netCapability : netCapabilities) { + requestBuilder.addCapability(netCapability); } - return builder.build(); + + requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID); + mTestLooper.dispatchAll(); } @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - - requestListener.onNetworkRequested( - getNetworkRequestWithCapabilities(VcnGatewayConnectionConfigTest.EXPOSED_CAPS), - NETWORK_SCORE, - PROVIDER_ID); - mTestLooper.dispatchAll(); + startVcnGatewayWithCapabilities( + requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS); final Set gatewayConnections = mVcn.getVcnGatewayConnections(); assertFalse(gatewayConnections.isEmpty()); @@ -126,4 +146,38 @@ public class VcnTest { verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot)); } } + + @Test + public void testGatewayEnteringSafemodeNotifiesVcn() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + startVcnGatewayWithCapabilities(requestListener, capability); + } + + // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp. + // Expect one VcnGatewayConnection per capability. + final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length; + + final Set gatewayConnections = mVcn.getVcnGatewayConnections(); + assertEquals(numExpectedGateways, gatewayConnections.size()); + verify(mDeps, times(numExpectedGateways)) + .newVcnGatewayConnection( + eq(mVcnContext), + eq(TEST_SUB_GROUP), + eq(mSubscriptionSnapshot), + any(), + mGatewayStatusCallbackCaptor.capture()); + + // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down + // all Gateways + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onEnteredSafemode(); + mTestLooper.dispatchAll(); + + for (final VcnGatewayConnection gatewayConnection : gatewayConnections) { + verify(gatewayConnection).teardownAsynchronously(); + } + verify(mVcnNetworkProvider).unregisterListener(requestListener); + verify(mVcnSafemodeCallback).onEnteredSafemode(); + } } From 3bb13158778db9a0977903ac51f6bb9c901c87e0 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 3 Feb 2021 23:40:46 -0800 Subject: [PATCH 0050/1057] Remove use of locks in VcnGatewayConnection. This CL updates VcnGatewayConnection to not use locking for accesses to its TelephonySubscriptionSnapshot field. Instead, it will verify that the caller is running on the VCN-Looper. Because VcnGatewayConnection also runs on the VCN-Looper, this check guarantees that accesses to that field are safe even when not explicitly in a Handler event. Bug: 177364490 Test: atest FrameworksVcnTests Change-Id: I128a894cead739b88a77e37f4d829d33f6bfb26a --- .../server/vcn/VcnGatewayConnection.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index bd82fcc144..9ecdf1b487 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -61,7 +61,6 @@ import android.os.ParcelUuid; import android.util.ArraySet; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; @@ -404,9 +403,6 @@ public class VcnGatewayConnection extends StateMachine { @NonNull final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); - @NonNull private final Object mLock = new Object(); - - @GuardedBy("mLock") @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; @NonNull private final VcnContext mVcnContext; @@ -516,9 +512,7 @@ public class VcnGatewayConnection extends StateMachine { Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); - synchronized (mLock) { - mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); - } + mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback(); @@ -589,13 +583,10 @@ public class VcnGatewayConnection extends StateMachine { */ public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { Objects.requireNonNull(snapshot, "Missing snapshot"); + mVcnContext.ensureRunningOnLooperThread(); - // Vcn is the only user of this method and runs on the same Thread, but lock around - // mLastSnapshot to be technically correct. - synchronized (mLock) { - mLastSnapshot = snapshot; - mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot); - } + mLastSnapshot = snapshot; + mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot); sendMessage(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); } From 6b824c2d386de1294205970470b871a4a7d552c2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 5 Feb 2021 12:01:23 -0800 Subject: [PATCH 0051/1057] VDBG guard common verbose logging in Vcn This change ensures that debugging logs are not fired for the most common of cases. Test: atest FrameworksVcnTests Change-Id: I101d8949d5cfcf6d6cec5289ebc613c863d062e5 --- .../src/com/android/server/vcn/Vcn.java | 27 ++++++++++++++----- .../server/vcn/VcnNetworkProvider.java | 17 ++++++++---- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 5ec527a7d6..3726407211 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -16,6 +16,7 @@ package com.android.server.vcn; +import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.net.NetworkCapabilities; @@ -225,7 +226,7 @@ public class Vcn extends Handler { private void handleConfigUpdated(@NonNull VcnConfig config) { // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode() - Slog.v(getLogTag(), String.format("Config updated: config = %s", config.hashCode())); + Slog.v(getLogTag(), "Config updated: config = " + config.hashCode()); mConfig = config; @@ -251,17 +252,29 @@ public class Vcn extends Handler { private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { if (score > getNetworkScore()) { - Slog.v(getLogTag(), - "Request already satisfied by higher-scoring (" + score + ") network from " - + "provider " + providerId + ": " + request); + if (VDBG) { + Slog.v( + getLogTag(), + "Request already satisfied by higher-scoring (" + + score + + ") network from " + + "provider " + + providerId + + ": " + + request); + } return; } // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.v(getLogTag(), - "Request already satisfied by existing VcnGatewayConnection: " + request); + if (VDBG) { + Slog.v( + getLogTag(), + "Request already satisfied by existing VcnGatewayConnection: " + + request); + } return; } } @@ -308,7 +321,7 @@ public class Vcn extends Handler { } private String getLogTag() { - return String.format("%s [%d]", TAG, mSubscriptionGroup.hashCode()); + return TAG + " [" + mSubscriptionGroup.hashCode() + "]"; } /** Retrieves the network score for a VCN Network */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index fe4ea30361..bfeec011a2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static com.android.server.VcnManagementService.VDBG; + import android.annotation.NonNull; import android.content.Context; import android.net.NetworkProvider; @@ -83,11 +85,16 @@ public class VcnNetworkProvider extends NetworkProvider { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { - Slog.v( - TAG, - String.format( - "Network requested: Request = %s, score = %d, providerId = %d", - request, score, providerId)); + if (VDBG) { + Slog.v( + TAG, + "Network requested: Request = " + + request + + ", score = " + + score + + ", providerId = " + + providerId); + } final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId); From a25d2a57708676b519abf390ea9a02f8c65b1110 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 20 Jan 2021 20:32:02 -0800 Subject: [PATCH 0052/1057] Test Network startup in ConnectedState Add additional tests based on proxy implementations of ChildSessionCallback and ChildSessionConfiguration Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I165716a0212da7c06b9723656ffe35921cf81854 --- .../server/vcn/VcnGatewayConnection.java | 70 ++++++++++++++----- ...cnGatewayConnectionConnectedStateTest.java | 60 +++++++++++++++- .../vcn/VcnGatewayConnectionTestBase.java | 19 ++++- 3 files changed, 129 insertions(+), 20 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 9ecdf1b487..4d5cf4ff75 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -75,6 +75,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -297,9 +298,9 @@ public class VcnGatewayConnection extends StateMachine { private static final int EVENT_SETUP_COMPLETED = 6; private static class EventSetupCompletedInfo implements EventInfo { - @NonNull public final ChildSessionConfiguration childSessionConfig; + @NonNull public final VcnChildSessionConfiguration childSessionConfig; - EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) { + EventSetupCompletedInfo(@NonNull VcnChildSessionConfiguration childSessionConfig) { this.childSessionConfig = Objects.requireNonNull(childSessionConfig); } @@ -471,7 +472,7 @@ public class VcnGatewayConnection extends StateMachine { *

    Set in Connected and Migrating states, always @NonNull in Connected, Migrating * states, @Nullable otherwise. */ - private ChildSessionConfiguration mChildConfig; + private VcnChildSessionConfiguration mChildConfig; /** * The active network agent. @@ -659,7 +660,7 @@ public class VcnGatewayConnection extends StateMachine { new EventTransformCreatedInfo(direction, transform)); } - private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) { + private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) { sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig)); } @@ -1008,7 +1009,7 @@ public class VcnGatewayConnection extends StateMachine { protected void updateNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, @NonNull NetworkAgent agent, - @NonNull ChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying); final LinkProperties lp = @@ -1020,7 +1021,7 @@ public class VcnGatewayConnection extends StateMachine { protected NetworkAgent buildNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, - @NonNull ChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying); final LinkProperties lp = @@ -1068,15 +1069,15 @@ public class VcnGatewayConnection extends StateMachine { protected void setupInterface( int token, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull ChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig) { setupInterface(token, tunnelIface, childConfig, null); } protected void setupInterface( int token, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull ChildSessionConfiguration childConfig, - @Nullable ChildSessionConfiguration oldChildConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @Nullable VcnChildSessionConfiguration oldChildConfig) { try { final Set newAddrs = new ArraySet<>(childConfig.getInternalAddresses()); @@ -1189,7 +1190,7 @@ public class VcnGatewayConnection extends StateMachine { protected void setupInterfaceAndNetworkAgent( int token, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull ChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig) { setupInterface(token, tunnelIface, childConfig); if (mNetworkAgent == null) { @@ -1277,7 +1278,7 @@ public class VcnGatewayConnection extends StateMachine { private static LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull ChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig) { final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -1328,17 +1329,25 @@ public class VcnGatewayConnection extends StateMachine { } } - private class ChildSessionCallbackImpl implements ChildSessionCallback { + /** Implementation of ChildSessionCallback, exposed for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public class VcnChildSessionCallback implements ChildSessionCallback { private final int mToken; - ChildSessionCallbackImpl(int token) { + VcnChildSessionCallback(int token) { mToken = token; } + /** Internal proxy method for injecting of mocked ChildSessionConfiguration */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + void onOpened(@NonNull VcnChildSessionConfiguration childConfig) { + Slog.v(TAG, "ChildOpened for token " + mToken); + childOpened(mToken, childConfig); + } + @Override public void onOpened(@NonNull ChildSessionConfiguration childConfig) { - Slog.v(TAG, "ChildOpened for token " + mToken); - childOpened(mToken, childConfig); + onOpened(new VcnChildSessionConfiguration(childConfig)); } @Override @@ -1421,7 +1430,7 @@ public class VcnGatewayConnection extends StateMachine { buildIkeParams(), buildChildParams(), new IkeSessionCallbackImpl(token), - new ChildSessionCallbackImpl(token)); + new VcnChildSessionCallback(token)); } /** External dependencies used by VcnGatewayConnection, for injection in tests */ @@ -1458,6 +1467,35 @@ public class VcnGatewayConnection extends StateMachine { } } + /** + * Proxy implementation of Child Session Configuration, used for testing. + * + *

    This wrapper allows mocking of the final, parcelable ChildSessionConfiguration object for + * testing purposes. This is the unfortunate result of mockito-inline (for mocking final + * classes) not working properly with system services & associated classes. + * + *

    This class MUST EXCLUSIVELY be a passthrough, proxying calls directly to the actual + * ChildSessionConfiguration. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnChildSessionConfiguration { + private final ChildSessionConfiguration mChildConfig; + + public VcnChildSessionConfiguration(ChildSessionConfiguration childConfig) { + mChildConfig = childConfig; + } + + /** Retrieves the addresses to be used inside the tunnel. */ + public List getInternalAddresses() { + return mChildConfig.getInternalAddresses(); + } + + /** Retrieves the DNS servers to be used inside the tunnel. */ + public List getInternalDnsServers() { + return mChildConfig.getInternalDnsServers(); + } + } + /** Proxy implementation of IKE session, used for testing. */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class VcnIkeSession { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index e20070ee4f..278d93a1b1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -18,22 +18,35 @@ package com.android.server.vcn; import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; + 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 java.util.Collections; /** Tests for VcnGatewayConnection.ConnectedState */ @RunWith(AndroidJUnit4.class) @@ -106,6 +119,51 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } + @Test + public void testChildOpenedRegistersNetwork() throws Exception { + final VcnChildSessionConfiguration mMockChildSessionConfig = + mock(VcnChildSessionConfiguration.class); + doReturn(Collections.singletonList(TEST_INTERNAL_ADDR)) + .when(mMockChildSessionConfig) + .getInternalAddresses(); + doReturn(Collections.singletonList(TEST_DNS_ADDR)) + .when(mMockChildSessionConfig) + .getInternalDnsServers(); + + getChildSessionCallback().onOpened(mMockChildSessionConfig); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + + final ArgumentCaptor lpCaptor = + ArgumentCaptor.forClass(LinkProperties.class); + final ArgumentCaptor ncCaptor = + ArgumentCaptor.forClass(NetworkCapabilities.class); + verify(mConnMgr) + .registerNetworkAgent( + any(), + any(), + lpCaptor.capture(), + ncCaptor.capture(), + anyInt(), + any(), + anyInt()); + verify(mIpSecSvc) + .addAddressToTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any()); + + final LinkProperties lp = lpCaptor.getValue(); + assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses()); + assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers()); + + final NetworkCapabilities nc = ncCaptor.getValue(); + assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + for (int cap : mConfig.getAllExposedCapabilities()) { + assertTrue(nc.hasCapability(cap)); + } + } + @Test public void testChildSessionClosedTriggersDisconnect() throws Exception { getChildSessionCallback().onClosed(); @@ -122,6 +180,4 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); } - - // TODO: Add tests for childOpened() when ChildSessionConfiguration can be mocked or created } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 333b5b990d..d449eab494 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -27,10 +27,13 @@ import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.InetAddresses; import android.net.IpSecConfig; import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.IpSecTunnelInterfaceResponse; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -44,15 +47,22 @@ import android.os.test.TestLooper; import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; import org.junit.Before; import org.mockito.ArgumentCaptor; +import java.net.InetAddress; import java.util.Collections; import java.util.UUID; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final InetAddress TEST_DNS_ADDR = + InetAddresses.parseNumericAddress("2001:DB8:0:1::"); + protected static final LinkAddress TEST_INTERNAL_ADDR = + new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64); + protected static final int TEST_IPSEC_SPI_VALUE = 0x1234; protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1; protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2; @@ -86,6 +96,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @NonNull protected final IpSecService mIpSecSvc; + @NonNull protected final ConnectivityManager mConnMgr; protected VcnIkeSession mMockIkeSession; protected VcnGatewayConnection mGatewayConnection; @@ -103,6 +114,10 @@ public class VcnGatewayConnectionTestBase { mIpSecSvc = mock(IpSecService.class); setupIpSecManager(mContext, mIpSecSvc); + mConnMgr = mock(ConnectivityManager.class); + VcnTestUtils.setupSystemService( + mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); @@ -145,10 +160,10 @@ public class VcnGatewayConnectionTestBase { return captor.getValue(); } - protected ChildSessionCallback getChildSessionCallback() { + protected VcnChildSessionCallback getChildSessionCallback() { ArgumentCaptor captor = ArgumentCaptor.forClass(ChildSessionCallback.class); verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture()); - return captor.getValue(); + return (VcnChildSessionCallback) captor.getValue(); } } From f91e1f57b180ea1b108116bc927084abcf5d8528 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Oct 2020 17:58:37 -0700 Subject: [PATCH 0053/1057] Implement RetryTimeout state This change adds support for retries with incrementally increasing delays. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: I414dce5882540bbe338d0bc1f40481df424821fe --- .../server/vcn/VcnGatewayConnection.java | 59 +++++++++++++- ...atewayConnectionRetryTimeoutStateTest.java | 78 +++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 4d5cf4ff75..2503e812f9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1208,7 +1208,64 @@ public class VcnGatewayConnection extends StateMachine { */ class RetryTimeoutState extends ActiveBaseState { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() throws Exception { + // Reset upon entry to ConnectedState + mFailedAttempts++; + + if (mUnderlying == null) { + Slog.wtf(TAG, "Underlying network was null in retry state"); + transitionTo(mDisconnectedState); + } else { + sendMessageDelayed( + EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken, getNextRetryIntervalsMs()); + } + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: + final UnderlyingNetworkRecord oldUnderlying = mUnderlying; + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + // If new underlying is null, all networks were lost; go back to disconnected. + if (mUnderlying == null) { + removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED); + + transitionTo(mDisconnectedState); + return; + } else if (oldUnderlying != null + && mUnderlying.network.equals(oldUnderlying.network)) { + // If the network has not changed, do nothing. + return; + } + + // Fallthrough + case EVENT_RETRY_TIMEOUT_EXPIRED: + removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED); + + transitionTo(mConnectingState); + break; + case EVENT_DISCONNECT_REQUESTED: + handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + break; + default: + logUnhandledMessage(msg); + break; + } + } + + private long getNextRetryIntervalsMs() { + final int retryDelayIndex = mFailedAttempts - 1; + final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs(); + + // Repeatedly use last item in retry timeout list. + if (retryDelayIndex >= retryIntervalsMs.length) { + return retryIntervalsMs[retryIntervalsMs.length - 1]; + } + + return retryIntervalsMs[retryDelayIndex]; + } } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java new file mode 100644 index 0000000000..3f2b47cd58 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -0,0 +1,78 @@ +/* + * 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.vcn; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for VcnGatewayConnection.RetryTimeoutState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase { + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); + mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); + mTestLooper.dispatchAll(); + } + + @Test + public void testNewNetworkTriggerRetry() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testSameNetworkDoesNotTriggerRetry() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testNullNetworkTriggersDisconnect() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testTimeoutElapsingTriggersRetry() throws Exception { + mTestLooper.moveTimeForward(mConfig.getRetryIntervalsMs()[0]); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + } +} From a675ee97faeb1d9fdda732294e8c3181cd490b05 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Sun, 7 Feb 2021 11:37:19 -0800 Subject: [PATCH 0054/1057] Fix PolicyListener testing surface. This CL updates VcnManager to provide a test-only method for getting currently registered VcnUnderlyingNetworkPolicyListeners. This is preferrable over the current method, which accesses VcnManager's private Map directly. Bug: 8675309 Test: atest FrameworksVcnTests Change-Id: I7afd60ff55868ae44bfa74910ae02daf8a81b107 --- .../src/android/net/vcn/VcnManager.java | 17 +++++++++++++++-- .../java/android/net/vcn/VcnManagerTest.java | 6 +++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index fa090f59a8..1a38338c26 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -28,8 +28,10 @@ import android.os.RemoteException; import android.os.ServiceSpecificException; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import java.io.IOException; +import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -67,8 +69,7 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - @VisibleForTesting - public static final Map< + private static final Map< VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @@ -88,6 +89,18 @@ public class VcnManager { mService = requireNonNull(service, "missing service"); } + /** + * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes. + * + * @hide + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + public static Map + getAllPolicyListeners() { + return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); + } + // TODO: Make setVcnConfig(), clearVcnConfig() Public API /** * Sets the VCN configuration for a given subscription group. diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index f9db408462..7dada9d1b6 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -65,7 +65,7 @@ public class VcnManagerTest { ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class); verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture()); - assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + assertTrue(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener)); IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue(); listenerWrapper.onPolicyChanged(); @@ -78,7 +78,7 @@ public class VcnManagerTest { mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener)); verify(mMockVcnManagementService) .addVcnUnderlyingNetworkPolicyListener( any(IVcnUnderlyingNetworkPolicyListener.class)); @@ -88,7 +88,7 @@ public class VcnManagerTest { public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception { mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener)); verify(mMockVcnManagementService, never()) .addVcnUnderlyingNetworkPolicyListener( any(IVcnUnderlyingNetworkPolicyListener.class)); From a7a3fdf42c41568da92a38f3471c29842a33eb45 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Feb 2021 22:21:46 -0800 Subject: [PATCH 0055/1057] Restrict Carrier Wifi while VCN is configured & privileged This change removes the NOT_RESTRICTED capability for Carrier Wifi. This is done even if a VCN is in safe mode, but will ONLY be performed if the VCN is provisioned, and has the appropriate carrier privileges to run. This change also fixes a test bug where the NOT_VCN_MANAGED capability was not present in the query to getUnderlyingNetworkPolicy(), and therefore was incorrectly passing. Bug: 163432273 Test: atest FrameworksVcnTests Change-Id: Iecb827b5341bdeb93ef8692c1d62f0eaf9d416ba --- .../android/server/VcnManagementService.java | 17 ++- .../server/VcnManagementServiceTest.java | 129 +++++++++++++----- 2 files changed, 113 insertions(+), 33 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 4dce59f23a..27210daac2 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -641,21 +641,34 @@ public class VcnManagementService extends IVcnManagementService.Stub { } boolean isVcnManagedNetwork = false; + boolean isRestrictedCarrierWifi = false; if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { synchronized (mLock) { ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); Vcn vcn = mVcns.get(subGroup); - if (vcn != null && vcn.isActive()) { - isVcnManagedNetwork = true; + if (vcn != null) { + if (vcn.isActive()) { + isVcnManagedNetwork = true; + } + + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + // Carrier WiFi always restricted if VCN exists (even in safe mode). + isRestrictedCarrierWifi = true; + } } } } + if (isVcnManagedNetwork) { networkCapabilities.removeCapability( NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } + if (isRestrictedCarrierWifi) { + networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 485964487f..c290bff188 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -16,6 +16,10 @@ package com.android.server; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; import static com.android.server.vcn.VcnTestUtils.setupSystemService; @@ -106,6 +110,7 @@ public class VcnManagementServiceTest { Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG)); private static final int TEST_SUBSCRIPTION_ID = 1; + private static final int TEST_SUBSCRIPTION_ID_2 = 2; private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO = new SubscriptionInfo( TEST_SUBSCRIPTION_ID /* id */, @@ -537,59 +542,121 @@ public class VcnManagementServiceTest { Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup)); } - private void verifyMergedNetworkCapabilitiesIsVcnManaged( - NetworkCapabilities mergedCapabilities, @Transport int transportType) { + private void verifyMergedNetworkCapabilities( + NetworkCapabilities mergedCapabilities, + @Transport int transportType, + boolean isVcnManaged, + boolean isRestricted) { assertTrue(mergedCapabilities.hasTransport(transportType)); - assertFalse( + assertEquals( + !isVcnManaged, mergedCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); + assertEquals( + !isRestricted, + mergedCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); + } + + private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) { + setUpVcnSubscription(subId, subGrp); + final Vcn vcn = startAndGetVcnInstance(subGrp); + doReturn(isVcnActive).when(vcn).isActive(); + } + + private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport( + int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) { + setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); + + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(); + ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + if (transport == TRANSPORT_CELLULAR) { + ncBuilder + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); + } else if (transport == TRANSPORT_WIFI) { + WifiInfo wifiInfo = mock(WifiInfo.class); + when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); + when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); + + ncBuilder + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setTransportInfo(wifiInfo); + } else { + throw new IllegalArgumentException("Unknown transport"); + } + + return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties()); } @Test public void testGetUnderlyingNetworkPolicyCellular() throws Exception { - setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); - - NetworkCapabilities nc = - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)) - .build(); - - VcnUnderlyingNetworkPolicy policy = - mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); + final VcnUnderlyingNetworkPolicy policy = + startVcnAndGetPolicyForTransport( + TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR); assertFalse(policy.isTeardownRequested()); - verifyMergedNetworkCapabilitiesIsVcnManaged( - policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), + TRANSPORT_CELLULAR, + true /* isVcnManaged */, + false /* isRestricted */); + } + + @Test + public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception { + final VcnUnderlyingNetworkPolicy policy = + startVcnAndGetPolicyForTransport( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + false /* isActive */, + TRANSPORT_CELLULAR); + + assertFalse(policy.isTeardownRequested()); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), + NetworkCapabilities.TRANSPORT_CELLULAR, + false /* isVcnManaged */, + false /* isRestricted */); } @Test public void testGetUnderlyingNetworkPolicyWifi() throws Exception { - setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2); - - WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); - when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); - NetworkCapabilities nc = - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setTransportInfo(wifiInfo) - .build(); - - VcnUnderlyingNetworkPolicy policy = - mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties()); + final VcnUnderlyingNetworkPolicy policy = + startVcnAndGetPolicyForTransport( + TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI); assertFalse(policy.isTeardownRequested()); - verifyMergedNetworkCapabilitiesIsVcnManaged( - policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), + NetworkCapabilities.TRANSPORT_WIFI, + true /* isVcnManaged */, + true /* isRestricted */); + } + + @Test + public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception { + final VcnUnderlyingNetworkPolicy policy = + startVcnAndGetPolicyForTransport( + TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI); + + assertFalse(policy.isTeardownRequested()); + verifyMergedNetworkCapabilities( + policy.getMergedNetworkCapabilities(), + NetworkCapabilities.TRANSPORT_WIFI, + false /* isVcnManaged */, + true /* isRestricted */); } @Test public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception { + setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */); + NetworkCapabilities nc = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2)) .build(); VcnUnderlyingNetworkPolicy policy = From c76951f7370c619825f3d10bdd9d3cf56c1b9ffa Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 9 Feb 2021 18:41:01 -0800 Subject: [PATCH 0056/1057] Lazy-create IpSecTunnelInterface With the Network(int) constructor moving to mainline, we cannot use the constructor, and should just create the IpSecTunnelInterface lazily, at first use. Bug: 165827287 Test: atest FrameworksVcnTests Change-Id: Ic01858e0f9c80d316676cfbae5edca114655c3fe --- .../server/vcn/VcnGatewayConnection.java | 40 ++++++++++--------- ...atewayConnectionDisconnectedStateTest.java | 11 +++++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 2503e812f9..37d13fb86d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -125,10 +125,11 @@ import java.util.concurrent.TimeUnit; public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); + private static final int[] MERGED_CAPABILITIES = new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING}; - - private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE; private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: "; @@ -412,11 +413,11 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull private final Dependencies mDeps; - @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; @NonNull private final IpSecManager mIpSecManager; - @NonNull private final IpSecTunnelInterface mTunnelIface; + + @Nullable private IpSecTunnelInterface mTunnelIface = null; /** Running state of this VcnGatewayConnection. */ private boolean mIsRunning = true; @@ -526,20 +527,6 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); - IpSecTunnelInterface iface; - try { - iface = - mIpSecManager.createIpSecTunnelInterface( - DUMMY_ADDR, DUMMY_ADDR, new Network(-1)); - } catch (IOException | ResourceUnavailableException e) { - teardownAsynchronously(); - mTunnelIface = null; - - return; - } - - mTunnelIface = iface; - addState(mDisconnectedState); addState(mDisconnectingState); addState(mConnectingState); @@ -1117,6 +1104,18 @@ public class VcnGatewayConnection extends StateMachine { class ConnectedState extends ConnectedStateBase { @Override protected void enterState() throws Exception { + if (mTunnelIface == null) { + try { + // Requires a real Network object in order to be created; doing this any earlier + // means not having a real Network object, or picking an incorrect Network. + mTunnelIface = + mIpSecManager.createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, mUnderlying.network); + } catch (IOException | ResourceUnavailableException e) { + teardownAsynchronously(); + } + } + // Successful connection, clear failed attempt counter mFailedAttempts = 0; } @@ -1433,6 +1432,11 @@ public class VcnGatewayConnection extends StateMachine { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setTunnelInterface(IpSecTunnelInterface tunnelIface) { + mTunnelIface = tunnelIface; + } + @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() { return mUnderlyingNetworkTrackerCallback; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 8643d8a2ea..16181b6f83 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -16,12 +16,18 @@ package com.android.server.vcn; +import static android.net.IpSecManager.IpSecTunnelInterface; + +import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; +import android.net.IpSecManager; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -37,6 +43,11 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect public void setUp() throws Exception { super.setUp(); + final IpSecTunnelInterface tunnelIface = + mContext.getSystemService(IpSecManager.class) + .createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); + mGatewayConnection.setTunnelInterface(tunnelIface); mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState); mTestLooper.dispatchAll(); } From 7d97896bd2747af9a483970f3b69680a8e6f58ba Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 10 Feb 2021 17:22:47 -0800 Subject: [PATCH 0057/1057] Add bug component for VCN CTS Test: no code changes Change-Id: I100787db26ef7507e13324f3ff53ae082a01a074 --- Vcn/tests/cts/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS index 350d2db8eb..376bd5a78a 100644 --- a/Vcn/tests/cts/OWNERS +++ b/Vcn/tests/cts/OWNERS @@ -1,2 +1,3 @@ +# Bug component: 826680 nharold@google.com junyin@google.com \ No newline at end of file From a0c7881b11a68927a844e6a922b50cea85d0d9af Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 10 Feb 2021 22:29:33 -0800 Subject: [PATCH 0058/1057] Change Bug component to an android-root component Test: Owners changes only, no code changes Change-Id: Id4a81d5da56535af9868ce290d3aa8602ff02830 --- Vcn/tests/cts/OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS index 376bd5a78a..574aa9f118 100644 --- a/Vcn/tests/cts/OWNERS +++ b/Vcn/tests/cts/OWNERS @@ -1,3 +1,3 @@ -# Bug component: 826680 +# Bug component: 685852 nharold@google.com junyin@google.com \ No newline at end of file From 91a818650a584081c1fc69b02ef6305f1b55620b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 1 Feb 2021 16:05:29 -0800 Subject: [PATCH 0059/1057] Add basic VCN tests This change adds the basics of the VCN CTS tests, granting carrier privileges and conditioning on the FEATURE_TELEPHONY Bug: 179228925 Test: atest CtsVcnTestCases Change-Id: Iee3f5dc03869a9d761807ee1c33b008c9a46d42d --- Vcn/tests/cts/Android.bp | 46 +++++++ Vcn/tests/cts/AndroidManifest.xml | 40 ++++++ Vcn/tests/cts/AndroidTest.xml | 32 +++++ .../android/net/vcn/cts/VcnManagerTest.java | 116 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 Vcn/tests/cts/Android.bp create mode 100644 Vcn/tests/cts/AndroidManifest.xml create mode 100644 Vcn/tests/cts/AndroidTest.xml create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp new file mode 100644 index 0000000000..5666ee78a5 --- /dev/null +++ b/Vcn/tests/cts/Android.bp @@ -0,0 +1,46 @@ +// 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. + +android_test { + name: "CtsVcnTestCases", + defaults: ["cts_defaults"], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", + + libs: [ + "android.test.base", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "androidx.test.ext.junit", + "compatibility-device-util-axt", + "ctstestrunner-axt", + "net-tests-utils", + "telephony-cts-utils", + ], + + platform_apis: true, + + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "vts", + "general-tests", + ], +} diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml new file mode 100644 index 0000000000..ba6cc45401 --- /dev/null +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Vcn/tests/cts/AndroidTest.xml b/Vcn/tests/cts/AndroidTest.xml new file mode 100644 index 0000000000..519b88a43b --- /dev/null +++ b/Vcn/tests/cts/AndroidTest.xml @@ -0,0 +1,32 @@ + + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java new file mode 100644 index 0000000000..8f2c3a6c48 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -0,0 +1,116 @@ +/* + * 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 android.net.vcn.cts; + +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnManager; +import android.os.ParcelUuid; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.cts.util.CarrierPrivilegeUtils; +import android.telephony.cts.util.SubscriptionGroupUtils; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class VcnManagerTest { + private static final String TAG = VcnManagerTest.class.getSimpleName(); + + private final Context mContext; + private final VcnManager mVcnManager; + private final SubscriptionManager mSubscriptionManager; + private final TelephonyManager mTelephonyManager; + + public VcnManagerTest() { + mContext = InstrumentationRegistry.getContext(); + mVcnManager = mContext.getSystemService(VcnManager.class); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + } + + @Before + public void setUp() throws Exception { + assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); + } + + private VcnConfig buildVcnConfig() { + final VcnGatewayConnectionConfig gatewayConnConfig = + new VcnGatewayConnectionConfig.Builder() + .addExposedCapability(NET_CAPABILITY_INTERNET) + .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) + .setRetryInterval( + new long[] { + TimeUnit.SECONDS.toMillis(1), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.HOURS.toMillis(1) + }) + .setMaxMtu(1360) + .build(); + + return new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig(gatewayConnConfig) + .build(); + } + + @Test(expected = SecurityException.class) + public void testSetVcnConfig_noCarrierPrivileges() throws Exception { + mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig()); + } + + @Test + public void testSetVcnConfig_withCarrierPrivileges() throws Exception { + final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + }); + }); + + assertFalse(mTelephonyManager.createForSubscriptionId(dataSubId).hasCarrierPrivileges()); + } + + @Test(expected = SecurityException.class) + public void testClearVcnConfig_noCarrierPrivileges() throws Exception { + mVcnManager.clearVcnConfig(new ParcelUuid(UUID.randomUUID())); + } + + @Test + public void testClearVcnConfig_withCarrierPrivileges() throws Exception { + final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { + mVcnManager.clearVcnConfig(subGrp); + }); + }); + } +} From 521b59aad4a3d36b25401086776c0a23c09bd143 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 2 Feb 2021 18:53:18 -0800 Subject: [PATCH 0060/1057] Acquire WakeLock while processing Gateway messages. This CL updates VcnGatewayConnection to acquire a WakeLock when sending a message to the Handler queue. After every message is processed, the state will check for additional messages and release the WakeLock if the queue is empty. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: Ib108c834833cc8feb2c92c9a6c60f218618225ec --- .../server/vcn/VcnGatewayConnection.java | 292 +++++++++++++++--- .../server/vcn/VcnGatewayConnectionTest.java | 7 + .../vcn/VcnGatewayConnectionTestBase.java | 24 ++ 3 files changed, 280 insertions(+), 43 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 37d13fb86d..adacae542a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -27,6 +27,7 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; @@ -58,6 +59,8 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.util.ArraySet; import android.util.Slog; @@ -120,6 +123,15 @@ import java.util.concurrent.TimeUnit; * +----------------------------+ *

    * + *

    All messages in VcnGatewayConnection should be enqueued using {@link + * #sendMessageAndAcquireWakeLock}. Careful consideration should be given to any uses of {@link + * #sendMessage} directly, as they are not guaranteed to be processed in a timely manner (due to the + * lack of WakeLocks). + * + *

    Any attempt to remove messages from the Handler should be done using {@link + * #removeEqualMessages(int, Object)}. This is necessary to ensure that the WakeLock is correctly + * released when no messages remain in the Handler queue. + * * @hide */ public class VcnGatewayConnection extends StateMachine { @@ -419,6 +431,21 @@ public class VcnGatewayConnection extends StateMachine { @Nullable private IpSecTunnelInterface mTunnelIface = null; + /** + * WakeLock to be held when processing messages on the Handler queue. + * + *

    Used to prevent the device from going to sleep while there are VCN-related events to + * process for this VcnGatewayConnection. + * + *

    Obtain a WakeLock when enquing messages onto the Handler queue. Once all messages in the + * Handler queue have been processed, the WakeLock can be released and cleared. + * + *

    This WakeLock is also used for handling delayed messages by using WakeupMessages to send + * delayed messages to the Handler. When the WakeupMessage fires, it will obtain the WakeLock + * before enquing the delayed event to the Handler. + */ + @NonNull private final VcnWakeLock mWakeLock; + /** Running state of this VcnGatewayConnection. */ private boolean mIsRunning = true; @@ -518,6 +545,9 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback(); + mWakeLock = + mDeps.newWakeLock(mVcnContext.getContext(), PowerManager.PARTIAL_WAKE_LOCK, TAG); + mUnderlyingNetworkTracker = mDeps.newUnderlyingNetworkTracker( mVcnContext, @@ -544,7 +574,7 @@ public class VcnGatewayConnection extends StateMachine { *

    Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); @@ -560,6 +590,8 @@ public class VcnGatewayConnection extends StateMachine { mTunnelIface.close(); } + releaseWakeLock(); + mUnderlyingNetworkTracker.teardown(); } @@ -576,13 +608,16 @@ public class VcnGatewayConnection extends StateMachine { mLastSnapshot = snapshot; mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot); - sendMessage(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); + sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); } private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override public void onSelectedUnderlyingNetworkChanged( @Nullable UnderlyingNetworkRecord underlying) { + // TODO(b/180132994): explore safely removing this Thread check + mVcnContext.ensureRunningOnLooperThread(); + // TODO(b/179091925): Move the delayed-message handling to BaseState // If underlying is null, all underlying networks have been lost. Disconnect VCN after a @@ -593,62 +628,189 @@ public class VcnGatewayConnection extends StateMachine { TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); - } else if (getHandler() != null) { - // Cancel any existing disconnect due to loss of underlying network - // getHandler() can return null if the state machine has already quit. Since this is - // called from other classes, this condition must be verified. - - getHandler() - .removeEqualMessages( - EVENT_DISCONNECT_REQUESTED, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + } else { + // Cancel any existing disconnect due to previous loss of underlying network + removeEqualMessages( + EVENT_DISCONNECT_REQUESTED, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_UNDERLYING_NETWORK_CHANGED, TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); } } - private void sendMessage(int what, int token, EventInfo data) { + private void acquireWakeLock() { + mVcnContext.ensureRunningOnLooperThread(); + + if (mIsRunning) { + mWakeLock.acquire(); + } + } + + private void releaseWakeLock() { + mVcnContext.ensureRunningOnLooperThread(); + + mWakeLock.release(); + } + + /** + * Attempt to release mWakeLock - this can only be done if the Handler is null (meaning the + * StateMachine has been shutdown and thus has no business keeping the WakeLock) or if there are + * no more messags left to process in the Handler queue (at which point the WakeLock can be + * released until more messages must be processed). + */ + private void maybeReleaseWakeLock() { + final Handler handler = getHandler(); + if (handler == null || !handler.hasMessagesOrCallbacks()) { + releaseWakeLock(); + } + } + + @Override + public void sendMessage(int what) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(what); + } + + @Override + public void sendMessage(int what, Object obj) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(what, obj); + } + + @Override + public void sendMessage(int what, int arg1) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(what, arg1); + } + + @Override + public void sendMessage(int what, int arg1, int arg2) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(what, arg1, arg2); + } + + @Override + public void sendMessage(int what, int arg1, int arg2, Object obj) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(what, arg1, arg2, obj); + } + + @Override + public void sendMessage(Message msg) { + Slog.wtf( + TAG, + "sendMessage should not be used in VcnGatewayConnection. See" + + " sendMessageAndAcquireWakeLock()"); + super.sendMessage(msg); + } + + /** + * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not + * go to sleep before processing the sent message. + */ + private void sendMessageAndAcquireWakeLock(int what, int token) { + acquireWakeLock(); + super.sendMessage(what, token); + } + + /** + * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not + * go to sleep before processing the sent message. + */ + private void sendMessageAndAcquireWakeLock(int what, int token, EventInfo data) { + acquireWakeLock(); super.sendMessage(what, token, ARG_NOT_PRESENT, data); } - private void sendMessage(int what, int token, int arg2, EventInfo data) { + /** + * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not + * go to sleep before processing the sent message. + */ + private void sendMessageAndAcquireWakeLock(int what, int token, int arg2, EventInfo data) { + acquireWakeLock(); super.sendMessage(what, token, arg2, data); } + // TODO: remove this method once WakupMessage is used instead private void sendMessageDelayed(int what, int token, EventInfo data, long timeout) { super.sendMessageDelayed(what, token, ARG_NOT_PRESENT, data, timeout); } + // TODO: remove this method once WakupMessage is used instead private void sendMessageDelayed(int what, int token, int arg2, EventInfo data, long timeout) { super.sendMessageDelayed(what, token, arg2, data, timeout); } + /** + * Removes all messages matching the given parameters, and attempts to release mWakeLock if the + * Handler is empty. + * + * @param what the Message.what value to be removed + */ + private void removeEqualMessages(int what) { + removeEqualMessages(what, null /* obj */); + } + + /** + * Removes all messages matching the given parameters, and attempts to release mWakeLock if the + * Handler is empty. + * + * @param what the Message.what value to be removed + * @param obj the Message.obj to to be removed, or null if all messages matching Message.what + * should be removed + */ + private void removeEqualMessages(int what, @Nullable Object obj) { + final Handler handler = getHandler(); + if (handler != null) { + handler.removeEqualMessages(what, obj); + } + + maybeReleaseWakeLock(); + } + private void sessionLost(int token, @Nullable Exception exception) { - sendMessage(EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); + sendMessageAndAcquireWakeLock( + EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); } private void sessionClosed(int token, @Nullable Exception exception) { // SESSION_LOST MUST be sent before SESSION_CLOSED to ensure that the SM moves to the // Disconnecting state. sessionLost(token, exception); - sendMessage(EVENT_SESSION_CLOSED, token); + sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token); } private void childTransformCreated( int token, @NonNull IpSecTransform transform, int direction) { - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_TRANSFORM_CREATED, token, new EventTransformCreatedInfo(direction, transform)); } private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) { - sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig)); + sendMessageAndAcquireWakeLock( + EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig)); } private abstract class BaseState extends State { @@ -658,7 +820,7 @@ public class VcnGatewayConnection extends StateMachine { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( @@ -668,23 +830,48 @@ public class VcnGatewayConnection extends StateMachine { protected void enterState() throws Exception {} + /** + * Returns whether the given token is valid. + * + *

    By default, States consider any and all token to be 'valid'. + * + *

    States should override this method if they want to restrict message handling to + * specific tokens. + */ + protected boolean isValidToken(int token) { + return true; + } + /** * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng * builds. + * + *

    Here be dragons: processMessage() is final to ensure that mWakeLock is released once + * the Handler queue is empty. Future changes to processMessage() (or overrides to + * processMessage) MUST ensure that mWakeLock is correctly released. */ @Override - public boolean processMessage(Message msg) { + public final boolean processMessage(Message msg) { + final int token = msg.arg1; + if (!isValidToken(token)) { + Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); + return HANDLED; + } + try { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); } + // Attempt to release the WakeLock - only possible if the Handler queue is empty + maybeReleaseWakeLock(); + return HANDLED; } @@ -696,7 +883,7 @@ public class VcnGatewayConnection extends StateMachine { exitState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessage( + sendMessageAndAcquireWakeLock( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( @@ -800,24 +987,7 @@ public class VcnGatewayConnection extends StateMachine { } private abstract class ActiveBaseState extends BaseState { - /** - * Handles all incoming messages, discarding messages for previous networks. - * - *

    States that handle mobility events may need to override this method to receive - * messages for all underlying networks. - */ @Override - public boolean processMessage(Message msg) { - final int token = msg.arg1; - // Only process if a valid token is presented. - if (isValidToken(token)) { - return super.processMessage(msg); - } - - Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); - return HANDLED; - } - protected boolean isValidToken(int token) { return (token == TOKEN_ALL || token == mCurrentToken); } @@ -848,7 +1018,7 @@ public class VcnGatewayConnection extends StateMachine { protected void enterState() throws Exception { if (mIkeSession == null) { Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state."); - sendMessage(EVENT_SESSION_CLOSED, mCurrentToken); + sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken); return; } @@ -1229,7 +1399,7 @@ public class VcnGatewayConnection extends StateMachine { // If new underlying is null, all networks were lost; go back to disconnected. if (mUnderlying == null) { - removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED); + removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); transitionTo(mDisconnectedState); return; @@ -1241,7 +1411,7 @@ public class VcnGatewayConnection extends StateMachine { // Fallthrough case EVENT_RETRY_TIMEOUT_EXPIRED: - removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED); + removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); transitionTo(mConnectingState); break; @@ -1526,6 +1696,12 @@ public class VcnGatewayConnection extends StateMachine { ikeSessionCallback, childSessionCallback); } + + /** Builds a new WakeLock. */ + public VcnWakeLock newWakeLock( + @NonNull Context context, int wakeLockFlag, @NonNull String wakeLockTag) { + return new VcnWakeLock(context, wakeLockFlag, wakeLockTag); + } } /** @@ -1605,4 +1781,34 @@ public class VcnGatewayConnection extends StateMachine { mImpl.setNetwork(network); } } + + /** Proxy Implementation of WakeLock, used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnWakeLock { + private final WakeLock mImpl; + + public VcnWakeLock(@NonNull Context context, int flags, @NonNull String tag) { + final PowerManager powerManager = context.getSystemService(PowerManager.class); + mImpl = powerManager.newWakeLock(flags, tag); + mImpl.setReferenceCounted(false /* isReferenceCounted */); + } + + /** + * Acquire this WakeLock. + * + *

    Synchronize this action to minimize locking around WakeLock use. + */ + public synchronized void acquire() { + mImpl.acquire(); + } + + /** + * Release this Wakelock. + * + *

    Synchronize this action to minimize locking around WakeLock use. + */ + public synchronized void release() { + mImpl.release(); + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index bc6bee28d1..026ee4918d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -132,10 +132,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { @Test public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { + verifyWakeLockSetUp(); + final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot); verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot)); + verifyWakeLockAcquired(); + + mTestLooper.dispatchAll(); + + verifyWakeLockReleased(); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index d449eab494..133466f8d1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -21,9 +21,11 @@ import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; @@ -42,12 +44,14 @@ import android.net.ipsec.ike.IkeSessionCallback; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; +import android.os.PowerManager; import android.os.test.TestLooper; import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -94,6 +98,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull protected final VcnGatewayConnection.Dependencies mDeps; @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + @NonNull protected final VcnWakeLock mWakeLock; @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; @@ -110,6 +115,7 @@ public class VcnGatewayConnectionTestBase { mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class); mDeps = mock(VcnGatewayConnection.Dependencies.class); mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); + mWakeLock = mock(VcnWakeLock.class); mIpSecSvc = mock(IpSecService.class); setupIpSecManager(mContext, mIpSecSvc); @@ -125,6 +131,9 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) .newUnderlyingNetworkTracker(any(), any(), any(), any(), any()); + doReturn(mWakeLock) + .when(mDeps) + .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); } @Before @@ -166,4 +175,19 @@ public class VcnGatewayConnectionTestBase { verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture()); return (VcnChildSessionCallback) captor.getValue(); } + + protected void verifyWakeLockSetUp() { + verify(mDeps).newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); + verifyNoMoreInteractions(mWakeLock); + } + + protected void verifyWakeLockAcquired() { + verify(mWakeLock).acquire(); + verifyNoMoreInteractions(mWakeLock); + } + + protected void verifyWakeLockReleased() { + verify(mWakeLock).release(); + verifyNoMoreInteractions(mWakeLock); + } } From 240e543995767b01650a797080c068fecef5e5c7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 12 Feb 2021 16:14:42 -0800 Subject: [PATCH 0061/1057] Add CtsVcnTestCases to presubmit Test: atest CtsVcnTestCases Test: Treehugger runs CtsVcnTestCases Change-Id: I4c60ddc3afd3ecc3474dfb67aecdbf4b953fd9fc --- Vcn/tests/cts/TEST_MAPPING | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Vcn/tests/cts/TEST_MAPPING diff --git a/Vcn/tests/cts/TEST_MAPPING b/Vcn/tests/cts/TEST_MAPPING new file mode 100644 index 0000000000..f8ac08c2f2 --- /dev/null +++ b/Vcn/tests/cts/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsVcnTestCases" + } + ] +} \ No newline at end of file From 4ff7fad22a9abe4dc22dec9e13d80547bb2133e8 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 3 Feb 2021 16:12:05 -0800 Subject: [PATCH 0062/1057] Use WakeupMesage for delayed events in VcnGatewayConnection. This CL updates VcnGatewayConnection to use WakeupMessages instead of sendDelayedMessage() for delayed events. This change allows for VcnGatewayConnection to guarantee that all its messages are processed while holding WakeLocks. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: If8182378fe2e9dad08df88a84934b21e22e25752 --- .../server/vcn/VcnGatewayConnection.java | 193 +++++++++++++++--- ...cnGatewayConnectionConnectedStateTest.java | 3 + ...nGatewayConnectionConnectingStateTest.java | 4 + ...atewayConnectionDisconnectedStateTest.java | 1 + ...tewayConnectionDisconnectingStateTest.java | 22 +- ...atewayConnectionRetryTimeoutStateTest.java | 18 +- .../server/vcn/VcnGatewayConnectionTest.java | 15 ++ .../vcn/VcnGatewayConnectionTestBase.java | 63 ++++++ 8 files changed, 280 insertions(+), 39 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index adacae542a..8aab3a66ad 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -61,6 +61,7 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.PowerManager.WakeLock; +import android.os.SystemClock; import android.util.ArraySet; import android.util.Slog; @@ -68,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.internal.util.WakeupMessage; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; @@ -129,8 +131,8 @@ import java.util.concurrent.TimeUnit; * lack of WakeLocks). * *

    Any attempt to remove messages from the Handler should be done using {@link - * #removeEqualMessages(int, Object)}. This is necessary to ensure that the WakeLock is correctly - * released when no messages remain in the Handler queue. + * #removeEqualMessages}. This is necessary to ensure that the WakeLock is correctly released when + * no messages remain in the Handler queue. * * @hide */ @@ -140,6 +142,15 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String TEARDOWN_TIMEOUT_ALARM = TAG + "_TEARDOWN_TIMEOUT_ALARM"; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String DISCONNECT_REQUEST_ALARM = TAG + "_DISCONNECT_REQUEST_ALARM"; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String RETRY_TIMEOUT_ALARM = TAG + "_RETRY_TIMEOUT_ALARM"; + private static final int[] MERGED_CAPABILITIES = new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING}; private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE; @@ -150,7 +161,8 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ALL = Integer.MIN_VALUE; - private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; @VisibleForTesting(visibility = Visibility.PRIVATE) static final int TEARDOWN_TIMEOUT_SECONDS = 5; @@ -510,6 +522,10 @@ public class VcnGatewayConnection extends StateMachine { */ private NetworkAgent mNetworkAgent; + @Nullable private WakeupMessage mTeardownTimeoutAlarm; + @Nullable private WakeupMessage mDisconnectRequestAlarm; + @Nullable private WakeupMessage mRetryTimeoutAlarm; + public VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @@ -592,6 +608,10 @@ public class VcnGatewayConnection extends StateMachine { releaseWakeLock(); + cancelTeardownTimeoutAlarm(); + cancelDisconnectRequestAlarm(); + cancelRetryTimeoutAlarm(); + mUnderlyingNetworkTracker.teardown(); } @@ -623,17 +643,11 @@ public class VcnGatewayConnection extends StateMachine { // If underlying is null, all underlying networks have been lost. Disconnect VCN after a // timeout. if (underlying == null) { - sendMessageDelayed( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), - TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); + setDisconnectRequestAlarm(); } else { - // Cancel any existing disconnect due to previous loss of underlying network - removeEqualMessages( - EVENT_DISCONNECT_REQUESTED, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + // Received a new Network so any previous alarm is irrelevant - cancel + clear it, + // and cancel any queued EVENT_DISCONNECT_REQUEST messages + cancelDisconnectRequestAlarm(); } sendMessageAndAcquireWakeLock( @@ -724,6 +738,10 @@ public class VcnGatewayConnection extends StateMachine { super.sendMessage(msg); } + // TODO(b/180146061): also override and Log.wtf() other Message handling methods + // In mind are sendMessageDelayed(), sendMessageAtFrontOfQueue, removeMessages, and + // removeDeferredMessages + /** * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not * go to sleep before processing the sent message. @@ -751,14 +769,13 @@ public class VcnGatewayConnection extends StateMachine { super.sendMessage(what, token, arg2, data); } - // TODO: remove this method once WakupMessage is used instead - private void sendMessageDelayed(int what, int token, EventInfo data, long timeout) { - super.sendMessageDelayed(what, token, ARG_NOT_PRESENT, data, timeout); - } - - // TODO: remove this method once WakupMessage is used instead - private void sendMessageDelayed(int what, int token, int arg2, EventInfo data, long timeout) { - super.sendMessageDelayed(what, token, arg2, data, timeout); + /** + * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not + * go to sleep before processing the sent message. + */ + private void sendMessageAndAcquireWakeLock(Message msg) { + acquireWakeLock(); + super.sendMessage(msg); } /** @@ -788,6 +805,100 @@ public class VcnGatewayConnection extends StateMachine { maybeReleaseWakeLock(); } + private WakeupMessage createScheduledAlarm( + @NonNull String cmdName, Message delayedMessage, long delay) { + // WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable + // at the scheduled time. dispatchMessage() immediately executes and there may be queued + // events that resolve the scheduled alarm pending in the queue. So, use the Runnable to + // place the alarm event at the end of the queue with sendMessageAndAcquireWakeLock (which + // guarantees the device will stay awake). + final WakeupMessage alarm = + mDeps.newWakeupMessage( + mVcnContext, + getHandler(), + cmdName, + () -> sendMessageAndAcquireWakeLock(delayedMessage)); + alarm.schedule(mDeps.getElapsedRealTime() + delay); + return alarm; + } + + private void setTeardownTimeoutAlarm() { + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In + // either case, there is nothing to cancel. + if (mTeardownTimeoutAlarm != null) { + Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set"); + } + + final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken); + mTeardownTimeoutAlarm = + createScheduledAlarm( + TEARDOWN_TIMEOUT_ALARM, + delayedMessage, + TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS)); + } + + private void cancelTeardownTimeoutAlarm() { + if (mTeardownTimeoutAlarm != null) { + mTeardownTimeoutAlarm.cancel(); + mTeardownTimeoutAlarm = null; + } + + // Cancel any existing teardown timeouts + removeEqualMessages(EVENT_TEARDOWN_TIMEOUT_EXPIRED); + } + + private void setDisconnectRequestAlarm() { + // Only schedule a NEW alarm if none is already set. + if (mDisconnectRequestAlarm != null) { + return; + } + + final Message delayedMessage = + obtainMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + 0 /* arg2 */, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + mDisconnectRequestAlarm = + createScheduledAlarm( + DISCONNECT_REQUEST_ALARM, + delayedMessage, + TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); + } + + private void cancelDisconnectRequestAlarm() { + if (mDisconnectRequestAlarm != null) { + mDisconnectRequestAlarm.cancel(); + mDisconnectRequestAlarm = null; + } + + // Cancel any existing disconnect due to previous loss of underlying network + removeEqualMessages( + EVENT_DISCONNECT_REQUESTED, + new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + } + + private void setRetryTimeoutAlarm(long delay) { + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In + // either case, there is nothing to cancel. + if (mRetryTimeoutAlarm != null) { + Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set"); + } + + final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken); + mRetryTimeoutAlarm = createScheduledAlarm(RETRY_TIMEOUT_ALARM, delayedMessage, delay); + } + + private void cancelRetryTimeoutAlarm() { + if (mRetryTimeoutAlarm != null) { + mRetryTimeoutAlarm.cancel(); + mRetryTimeoutAlarm = null; + } + + removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); + } + private void sessionLost(int token, @Nullable Exception exception) { sendMessageAndAcquireWakeLock( EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); @@ -847,8 +958,8 @@ public class VcnGatewayConnection extends StateMachine { * builds. * *

    Here be dragons: processMessage() is final to ensure that mWakeLock is released once - * the Handler queue is empty. Future changes to processMessage() (or overrides to - * processMessage) MUST ensure that mWakeLock is correctly released. + * the Handler queue is empty. Future changes (or overrides) to processMessage() to MUST + * ensure that mWakeLock is correctly released. */ @Override public final boolean processMessage(Message msg) { @@ -1030,10 +1141,9 @@ public class VcnGatewayConnection extends StateMachine { } mIkeSession.close(); - sendMessageDelayed( - EVENT_TEARDOWN_TIMEOUT_EXPIRED, - mCurrentToken, - TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS)); + + // Safe to blindly set up, as it is cancelled and cleared on exiting this state + setTeardownTimeoutAlarm(); } @Override @@ -1084,6 +1194,8 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void exitState() throws Exception { mSkipRetryTimeout = false; + + cancelTeardownTimeoutAlarm(); } } @@ -1385,8 +1497,8 @@ public class VcnGatewayConnection extends StateMachine { Slog.wtf(TAG, "Underlying network was null in retry state"); transitionTo(mDisconnectedState); } else { - sendMessageDelayed( - EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken, getNextRetryIntervalsMs()); + // Safe to blindly set up, as it is cancelled and cleared on exiting this state + setRetryTimeoutAlarm(getNextRetryIntervalsMs()); } } @@ -1399,8 +1511,6 @@ public class VcnGatewayConnection extends StateMachine { // If new underlying is null, all networks were lost; go back to disconnected. if (mUnderlying == null) { - removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); - transitionTo(mDisconnectedState); return; } else if (oldUnderlying != null @@ -1411,8 +1521,6 @@ public class VcnGatewayConnection extends StateMachine { // Fallthrough case EVENT_RETRY_TIMEOUT_EXPIRED: - removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); - transitionTo(mConnectingState); break; case EVENT_DISCONNECT_REQUESTED: @@ -1424,6 +1532,11 @@ public class VcnGatewayConnection extends StateMachine { } } + @Override + public void exitState() { + cancelRetryTimeoutAlarm(); + } + private long getNextRetryIntervalsMs() { final int retryDelayIndex = mFailedAttempts - 1; final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs(); @@ -1702,6 +1815,20 @@ public class VcnGatewayConnection extends StateMachine { @NonNull Context context, int wakeLockFlag, @NonNull String wakeLockTag) { return new VcnWakeLock(context, wakeLockFlag, wakeLockTag); } + + /** Builds a new WakeupMessage. */ + public WakeupMessage newWakeupMessage( + @NonNull VcnContext vcnContext, + @NonNull Handler handler, + @NonNull String tag, + @NonNull Runnable runnable) { + return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable); + } + + /** Gets the elapsed real time since boot, in millis. */ + public long getElapsedRealTime() { + return SystemClock.elapsedRealtime(); + } } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 278d93a1b1..faa8b234cf 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -81,6 +81,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); verify(mIkeSession, never()).close(); + verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -170,6 +171,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -179,5 +181,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); + verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index d936183e5a..760379d664 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -61,6 +61,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verify(mIkeSession).kill(); + verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -73,6 +74,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); verify(mIkeSession, never()).kill(); + verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -92,6 +94,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); + verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -101,5 +104,6 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); + verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 16181b6f83..1a1787ac19 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -88,6 +88,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index d0fec55a68..b09f3a008c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -16,9 +16,9 @@ package com.android.server.vcn; -import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import androidx.test.filters.SmallTest; @@ -28,8 +28,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.concurrent.TimeUnit; - /** Tests for VcnGatewayConnection.DisconnectedState */ @RunWith(AndroidJUnit4.class) @SmallTest @@ -40,6 +38,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession()); + // ensure that mGatewayConnection has an underlying Network before entering + // DisconnectingState + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_2); mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState); mTestLooper.dispatchAll(); } @@ -49,12 +50,22 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec getIkeSessionCallback().onClosed(); mTestLooper.dispatchAll(); - assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); + verify(mMockIkeSession).close(); + verify(mMockIkeSession, never()).kill(); + verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */); } @Test public void testTimeoutExpired() throws Exception { - mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS)); + Runnable delayedEvent = + verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); + + // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages + // (which are mocked here). Directly invoke the runnable instead. This is still sufficient, + // since verifyTeardownTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled + // with the correct delay. + delayedEvent.run(); mTestLooper.dispatchAll(); verify(mMockIkeSession).kill(); @@ -67,5 +78,6 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 3f2b47cd58..d37e92f661 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -29,10 +29,14 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase { + private long mFirstRetryInterval; + @Before public void setUp() throws Exception { super.setUp(); + mFirstRetryInterval = mConfig.getRetryInterval()[0]; + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); mTestLooper.dispatchAll(); @@ -46,6 +50,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); } @Test @@ -56,6 +61,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); + verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */); } @Test @@ -66,13 +72,23 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); } @Test public void testTimeoutElapsingTriggersRetry() throws Exception { - mTestLooper.moveTimeForward(mConfig.getRetryIntervalsMs()[0]); + final Runnable delayedEvent = + verifyRetryTimeoutAlarmAndGetCallback( + mFirstRetryInterval, false /* expectCanceled */); + + // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages + // (which are mocked here). Directly invoke the runnable instead. This is still sufficient, + // since verifyRetryTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled + // with the correct delay. + delayedEvent.run(); mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 026ee4918d..748c792468 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -145,4 +145,19 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyWakeLockReleased(); } + + @Test + public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + + verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); + + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + + verify(mDisconnectRequestAlarm).cancel(); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 133466f8d1..0b44e03a5e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -22,8 +22,11 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -47,6 +50,7 @@ import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import com.android.internal.util.WakeupMessage; import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; @@ -59,6 +63,7 @@ import org.mockito.ArgumentCaptor; import java.net.InetAddress; import java.util.Collections; import java.util.UUID; +import java.util.concurrent.TimeUnit; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); @@ -72,6 +77,7 @@ public class VcnGatewayConnectionTestBase { protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2; protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3; protected static final int TEST_SUB_ID = 5; + protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( @@ -99,6 +105,9 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final VcnGatewayConnection.Dependencies mDeps; @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; @NonNull protected final VcnWakeLock mWakeLock; + @NonNull protected final WakeupMessage mTeardownTimeoutAlarm; + @NonNull protected final WakeupMessage mDisconnectRequestAlarm; + @NonNull protected final WakeupMessage mRetryTimeoutAlarm; @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; @@ -116,6 +125,9 @@ public class VcnGatewayConnectionTestBase { mDeps = mock(VcnGatewayConnection.Dependencies.class); mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); mWakeLock = mock(VcnWakeLock.class); + mTeardownTimeoutAlarm = mock(WakeupMessage.class); + mDisconnectRequestAlarm = mock(WakeupMessage.class); + mRetryTimeoutAlarm = mock(WakeupMessage.class); mIpSecSvc = mock(IpSecService.class); setupIpSecManager(mContext, mIpSecSvc); @@ -134,6 +146,16 @@ public class VcnGatewayConnectionTestBase { doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); + + setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM); + setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM); + setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM); + + doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime(); + } + + private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) { + doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any()); } @Before @@ -190,4 +212,45 @@ public class VcnGatewayConnectionTestBase { verify(mWakeLock).release(); verifyNoMoreInteractions(mWakeLock); } + + private Runnable verifyWakeupMessageSetUpAndGetCallback( + @NonNull String tag, + @NonNull WakeupMessage msg, + long delayInMillis, + boolean expectCanceled) { + ArgumentCaptor runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(tag), runnableCaptor.capture()); + + verify(mDeps, atLeastOnce()).getElapsedRealTime(); + verify(msg).schedule(ELAPSED_REAL_TIME + delayInMillis); + verify(msg, expectCanceled ? times(1) : never()).cancel(); + + return runnableCaptor.getValue(); + } + + protected Runnable verifyTeardownTimeoutAlarmAndGetCallback(boolean expectCanceled) { + return verifyWakeupMessageSetUpAndGetCallback( + VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM, + mTeardownTimeoutAlarm, + TimeUnit.SECONDS.toMillis(VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS), + expectCanceled); + } + + protected Runnable verifyDisconnectRequestAlarmAndGetCallback(boolean expectCanceled) { + return verifyWakeupMessageSetUpAndGetCallback( + VcnGatewayConnection.DISCONNECT_REQUEST_ALARM, + mDisconnectRequestAlarm, + TimeUnit.SECONDS.toMillis( + VcnGatewayConnection.NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS), + expectCanceled); + } + + protected Runnable verifyRetryTimeoutAlarmAndGetCallback( + long delayInMillis, boolean expectCanceled) { + return verifyWakeupMessageSetUpAndGetCallback( + VcnGatewayConnection.RETRY_TIMEOUT_ALARM, + mRetryTimeoutAlarm, + delayInMillis, + expectCanceled); + } } From 90aec2778a8a5da95283b1306783d1e91fef4fb3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 4 Feb 2021 17:31:22 -0800 Subject: [PATCH 0063/1057] Add VcnUnderlyingNetworkSpecifier This change adds a VcnUnderlyingNetworkSpecifier as hidden API, for internal use only. The purpose of the VcnUnderlyingNetworkSpecifier is to match the specifiers for ONLY underlying (Telephony|Wifi) networks, ensuring that the VCN does NOT create a routing loop Bug: 179439329 Test: atest FrameworksVcnTests Test: atest android.net.vcn Change-Id: I0e158e1889d4462c117c46d9038f58d5adcc7e30 --- .../vcn/VcnUnderlyingNetworkSpecifier.java | 125 ++++++++++++++++++ .../server/vcn/VcnGatewayConnection.java | 2 - .../VcnUnderlyingNetworkSpecifierTest.java | 61 +++++++++ 3 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkSpecifier.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkSpecifier.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkSpecifier.java new file mode 100644 index 0000000000..a97563724e --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkSpecifier.java @@ -0,0 +1,125 @@ +/* + * 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 android.net.vcn; + +import android.annotation.NonNull; +import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.ArrayUtils; + +import java.util.Arrays; +import java.util.Objects; + +/** + * NetworkSpecifier object for VCN underlying network requests. + * + *

    This matches any underlying network with the appropriate subIds. + * + * @hide + */ +public final class VcnUnderlyingNetworkSpecifier extends NetworkSpecifier implements Parcelable { + @NonNull private final int[] mSubIds; + + /** + * Builds a new VcnUnderlyingNetworkSpecifier with the given list of subIds + * + * @hide + */ + public VcnUnderlyingNetworkSpecifier(@NonNull int[] subIds) { + mSubIds = Objects.requireNonNull(subIds, "subIds were null"); + } + + /** + * Retrieves the list of subIds supported by this VcnUnderlyingNetworkSpecifier + * + * @hide + */ + @NonNull + @VisibleForTesting(visibility = Visibility.PRIVATE) + public int[] getSubIds() { + return mSubIds; + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public VcnUnderlyingNetworkSpecifier createFromParcel(Parcel in) { + int[] subIds = in.createIntArray(); + return new VcnUnderlyingNetworkSpecifier(subIds); + } + + @Override + public VcnUnderlyingNetworkSpecifier[] newArray(int size) { + return new VcnUnderlyingNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeIntArray(mSubIds); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mSubIds); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof VcnUnderlyingNetworkSpecifier)) { + return false; + } + + VcnUnderlyingNetworkSpecifier lhs = (VcnUnderlyingNetworkSpecifier) obj; + return Arrays.equals(mSubIds, lhs.mSubIds); + } + + @Override + public String toString() { + return new StringBuilder() + .append("VcnUnderlyingNetworkSpecifier [") + .append("mSubIds = ").append(Arrays.toString(mSubIds)) + .append("]") + .toString(); + } + + /** @hide */ + @Override + public boolean canBeSatisfiedBy(NetworkSpecifier other) { + if (other instanceof TelephonyNetworkSpecifier) { + return ArrayUtils.contains( + mSubIds, ((TelephonyNetworkSpecifier) other).getSubscriptionId()); + } + // TODO(b/180140053): Allow matching against WifiNetworkAgentSpecifier + + // MatchAllNetworkSpecifier matched in NetworkCapabilities. + return equals(other); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 37d13fb86d..ee36333eaa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1326,8 +1326,6 @@ public class VcnGatewayConnection extends StateMachine { } } - // TODO: Make a VcnNetworkSpecifier, and match all underlying subscription IDs. - return builder.build(); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java new file mode 100644 index 0000000000..2110d6ee7c --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java @@ -0,0 +1,61 @@ +/* + * 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 android.net.vcn; + +import static com.android.testutils.ParcelUtils.assertParcelSane; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.TelephonyNetworkSpecifier; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnUnderlyingNetworkSpecifierTest { + private static final int[] TEST_SUB_IDS = new int[] {1, 2, 3, 5}; + + @Test + public void testGetSubIds() { + final VcnUnderlyingNetworkSpecifier specifier = + new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS); + + assertEquals(TEST_SUB_IDS, specifier.getSubIds()); + } + + @Test + public void testParceling() { + final VcnUnderlyingNetworkSpecifier specifier = + new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS); + assertParcelSane(specifier, 1); + } + + @Test + public void testCanBeSatisfiedByTelephonyNetworkSpecifier() { + final TelephonyNetworkSpecifier telSpecifier = + new TelephonyNetworkSpecifier(TEST_SUB_IDS[0]); + + final VcnUnderlyingNetworkSpecifier specifier = + new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS); + assertTrue(specifier.canBeSatisfiedBy(telSpecifier)); + } +} From 2ed68f3d7bc1f477f26da9addbc6342531750078 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 17:07:05 -0800 Subject: [PATCH 0064/1057] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/base Added SPDX-license-identifier-Apache-2.0 to: apct-tests/perftests/autofill/Android.bp apct-tests/perftests/blobstore/Android.bp apct-tests/perftests/core/Android.bp apct-tests/perftests/core/apps/overlay/Android.bp apct-tests/perftests/core/apps/reources_manager/Android.bp apct-tests/perftests/core/jni/Android.bp apct-tests/perftests/multiuser/Android.bp apct-tests/perftests/multiuser/apps/dummyapp/Android.bp apct-tests/perftests/packagemanager/Android.bp apct-tests/perftests/packagemanager/apps/query-all/Android.bp apct-tests/perftests/textclassifier/Android.bp apct-tests/perftests/utils/Android.bp apct-tests/perftests/windowmanager/Android.bp apex/Android.bp apex/blobstore/framework/Android.bp apex/blobstore/service/Android.bp apex/jobscheduler/framework/Android.bp apex/jobscheduler/service/Android.bp apex/media/Android.bp apex/media/aidl/Android.bp apex/media/framework/Android.bp cmds/am/Android.bp cmds/app_process/Android.bp cmds/appops/Android.bp cmds/appwidget/Android.bp cmds/backup/Android.bp cmds/bmgr/Android.bp cmds/bootanimation/Android.bp cmds/bu/Android.bp cmds/content/Android.bp cmds/dpm/Android.bp cmds/hid/Android.bp cmds/hid/jni/Android.bp cmds/idmap2/Android.bp cmds/ime/Android.bp cmds/incident/Android.bp cmds/incident_helper/Android.bp cmds/incidentd/Android.bp cmds/input/Android.bp cmds/interrupter/Android.bp cmds/locksettings/Android.bp cmds/pm/Android.bp cmds/requestsync/Android.bp cmds/screencap/Android.bp cmds/sm/Android.bp cmds/svc/Android.bp cmds/telecom/Android.bp cmds/uiautomator/Android.bp cmds/uiautomator/cmds/uiautomator/Android.bp cmds/uiautomator/instrumentation/Android.bp cmds/uiautomator/library/Android.bp cmds/vr/Android.bp cmds/wm/Android.bp config/Android.bp core/java/android/service/wallpaper/Android.bp core/jni/Android.bp core/sysprop/Android.bp core/tests/BroadcastRadioTests/Android.bp core/tests/ConnectivityManagerTest/Android.bp core/tests/PackageInstallerSessions/Android.bp core/tests/PlatformCompatFramework/Android.bp core/tests/bandwidthtests/Android.bp core/tests/benchmarks/Android.bp core/tests/bluetoothtests/Android.bp core/tests/bugreports/Android.bp core/tests/coretests/Android.bp core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp core/tests/coretests/BinderProxyCountingTestApp/Android.bp core/tests/coretests/BinderProxyCountingTestService/Android.bp core/tests/coretests/BstatsTestApp/Android.bp core/tests/coretests/DisabledTestApp/Android.bp core/tests/coretests/EnabledTestApp/Android.bp core/tests/coretests/aidl/Android.bp core/tests/coretests/apks/Android.bp core/tests/coretests/apks/install/Android.bp core/tests/coretests/apks/install_bad_dex/Android.bp core/tests/coretests/apks/install_complete_package_info/Android.bp core/tests/coretests/apks/install_decl_perm/Android.bp core/tests/coretests/apks/install_jni_lib/Android.bp core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp core/tests/coretests/apks/install_loc_auto/Android.bp core/tests/coretests/apks/install_loc_internal/Android.bp core/tests/coretests/apks/install_loc_sdcard/Android.bp core/tests/coretests/apks/install_loc_unspecified/Android.bp core/tests/coretests/apks/install_use_perm_good/Android.bp core/tests/coretests/apks/install_uses_feature/Android.bp core/tests/coretests/apks/install_verifier_bad/Android.bp core/tests/coretests/apks/install_verifier_good/Android.bp core/tests/coretests/apks/keyset/Android.bp core/tests/coretests/apks/locales/Android.bp core/tests/coretests/apks/overlay_config/Android.bp core/tests/coretests/apks/version/Android.bp core/tests/coretests/apks/version_nosys/Android.bp core/tests/featureflagtests/Android.bp core/tests/hdmitests/Android.bp core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp core/tests/hosttests/test-apps/NoLocTestApp/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/SharedUid/32/Android.bp core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/64/Android.bp core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp core/tests/hosttests/test-apps/SimpleTestApp/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp core/tests/mockingcoretests/Android.bp core/tests/notificationtests/Android.bp core/tests/overlaytests/device/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp core/tests/overlaytests/host/Android.bp core/tests/overlaytests/remount/Android.bp core/tests/overlaytests/remount/test-apps/Overlay/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp core/tests/overlaytests/remount/test-apps/Target/Android.bp core/tests/packagemanagertests/Android.bp core/tests/privacytests/Android.bp core/tests/screenshothelpertests/Android.bp core/tests/systemproperties/Android.bp core/tests/utillib/Android.bp core/tests/utiltests/Android.bp core/tests/utiltests/jni/Android.bp core/tests/uwbtests/Android.bp core/xsd/Android.bp core/xsd/vts/Android.bp data/etc/Android.bp data/etc/car/Android.bp data/fonts/Android.bp data/keyboards/Android.mk drm/jni/Android.bp errorprone/Android.bp graphics/proto/Android.bp keystore/Android.bp keystore/tests/Android.bp libs/WindowManager/Jetpack/Android.bp libs/WindowManager/Shell/Android.bp libs/WindowManager/Shell/tests/Android.bp libs/androidfw/Android.bp libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp libs/hostgraphics/Android.bp libs/incident/Android.bp libs/input/Android.bp libs/input/tests/Android.bp libs/protoutil/Android.bp libs/services/Android.bp libs/storage/Android.bp libs/usb/tests/AccessoryChat/Android.bp libs/usb/tests/AccessoryChat/accessorychat/Android.bp location/lib/Android.bp location/tests/Android.bp location/tests/locationtests/Android.bp lowpan/tests/Android.bp media/Android.bp media/java/Android.bp media/java/android/media/tv/tunerresourcemanager/Android.bp media/jni/Android.bp media/jni/audioeffect/Android.bp media/jni/soundpool/Android.bp media/jni/soundpool/tests/Android.bp media/lib/remotedisplay/Android.bp media/lib/signer/Android.bp media/lib/tvremote/Android.bp media/lib/tvremote/tests/Android.bp media/mca/filterfw/Android.bp media/mca/filterfw/native/Android.bp media/mca/filterpacks/Android.bp media/mca/samples/CameraEffectsRecordingSample/Android.bp media/mca/tests/Android.bp media/native/midi/Android.bp media/packages/BluetoothMidiService/Android.bp media/packages/BluetoothMidiService/tests/unit/Android.bp media/tests/AudioPolicyTest/Android.bp media/tests/CameraBrowser/Android.bp media/tests/EffectsTest/Android.bp media/tests/MediaDump/Android.bp media/tests/MediaFrameworkTest/Android.bp media/tests/MediaRouter/Android.bp media/tests/MtpTests/Android.bp media/tests/ScoAudioTest/Android.bp media/tests/SoundPoolTest/Android.bp media/tests/TunerTest/Android.bp media/tests/audiotests/Android.bp media/tests/players/Android.bp mime/Android.bp native/android/Android.bp native/graphics/jni/Android.bp native/webview/loader/Android.bp nfc-extras/Android.bp nfc-extras/tests/Android.bp packages/AppPredictionLib/Android.bp packages/BackupEncryption/Android.bp packages/BackupEncryption/test/robolectric-integration/Android.bp packages/BackupEncryption/test/robolectric/Android.bp packages/BackupEncryption/test/unittest/Android.bp packages/BackupRestoreConfirmation/Android.bp packages/CarSystemUI/Android.bp packages/CarrierDefaultApp/Android.bp packages/CarrierDefaultApp/tests/unit/Android.bp packages/CompanionDeviceManager/Android.bp packages/Connectivity/framework/Android.bp packages/Connectivity/service/Android.bp packages/CtsShim/Android.bp packages/CtsShim/build/Android.bp packages/CtsShim/build/jni/Android.bp packages/DynamicSystemInstallationService/Android.bp packages/DynamicSystemInstallationService/tests/Android.bp packages/EasterEgg/Android.bp packages/EncryptedLocalTransport/Android.bp packages/ExtShared/Android.bp packages/ExternalStorageProvider/Android.bp packages/ExternalStorageProvider/tests/Android.bp packages/FakeOemFeatures/Android.bp packages/FusedLocation/Android.bp packages/InputDevices/Android.bp packages/LocalTransport/Android.bp packages/PackageInstaller/Android.bp packages/PrintRecommendationService/Android.bp packages/PrintSpooler/Android.bp packages/PrintSpooler/jni/Android.bp packages/PrintSpooler/tests/outofprocess/Android.bp packages/SettingsLib/ActionBarShadow/Android.bp packages/SettingsLib/ActionButtonsPreference/Android.bp packages/SettingsLib/AdaptiveIcon/Android.bp packages/SettingsLib/Android.bp packages/SettingsLib/AppPreference/Android.bp packages/SettingsLib/BarChartPreference/Android.bp packages/SettingsLib/DisplayDensityUtils/Android.bp packages/SettingsLib/EntityHeaderWidgets/Android.bp packages/SettingsLib/HelpUtils/Android.bp packages/SettingsLib/LayoutPreference/Android.bp packages/SettingsLib/ProgressBar/Android.bp packages/SettingsLib/RadioButtonPreference/Android.bp packages/SettingsLib/RestrictedLockUtils/Android.bp packages/SettingsLib/SchedulesProvider/Android.bp packages/SettingsLib/SearchProvider/Android.bp packages/SettingsLib/SearchWidget/Android.bp packages/SettingsLib/SettingsSpinner/Android.bp packages/SettingsLib/SettingsTheme/Android.bp packages/SettingsLib/Tile/Android.bp packages/SettingsLib/Utils/Android.bp packages/SettingsLib/search/Android.bp packages/SettingsLib/tests/integ/Android.bp packages/SettingsLib/tests/robotests/Android.bp packages/SettingsProvider/Android.bp packages/SharedStorageBackup/Android.bp packages/Shell/Android.bp packages/Shell/tests/Android.bp packages/SimAppDialog/Android.bp packages/SoundPicker/Android.bp packages/StatementService/Android.bp packages/SystemUI/Android.bp packages/SystemUI/plugin/Android.bp packages/SystemUI/plugin/ExamplePlugin/Android.bp packages/SystemUI/plugin_core/Android.bp packages/SystemUI/shared/Android.bp packages/VpnDialogs/Android.bp packages/WAPPushManager/Android.bp packages/WAPPushManager/tests/Android.bp packages/WallpaperBackup/Android.bp packages/WallpaperCropper/Android.bp packages/overlays/Android.mk packages/overlays/tests/Android.bp packages/services/PacProcessor/Android.bp packages/services/PacProcessor/jni/Android.bp packages/services/Proxy/Android.bp proto/Android.bp rs/jni/Android.mk samples/demo/haptic-assessment/Android.bp sax/tests/saxtests/Android.bp services/Android.bp services/accessibility/Android.bp services/appprediction/Android.bp services/appwidget/Android.bp services/autofill/Android.bp services/backup/Android.bp services/backup/backuplib/Android.bp services/companion/Android.bp services/contentcapture/Android.bp services/contentsuggestions/Android.bp services/core/Android.bp services/core/java/com/android/server/vcn/Android.bp services/core/jni/Android.bp services/core/xsd/Android.bp services/core/xsd/vts/Android.bp services/coverage/Android.bp services/devicepolicy/Android.bp services/incremental/Android.bp services/midi/Android.bp services/net/Android.bp services/people/Android.bp services/print/Android.bp services/profcollect/Android.bp services/restrictions/Android.bp services/robotests/Android.bp services/robotests/backup/Android.bp services/systemcaptions/Android.bp services/tests/PackageManagerComponentOverrideTests/Android.bp services/tests/PackageManagerServiceTests/host/Android.bp services/tests/PackageManagerServiceTests/host/test-apps/Android.bp services/tests/mockingservicestests/Android.bp services/tests/rescueparty/Android.bp services/tests/servicestests/Android.bp services/tests/servicestests/aidl/Android.bp services/tests/servicestests/apks/Android.bp services/tests/servicestests/apks/install-split-base/Android.bp services/tests/servicestests/apks/install-split-feature-a/Android.bp services/tests/servicestests/apks/install_intent_filters/Android.bp services/tests/servicestests/apks/install_uses_sdk/Android.bp services/tests/servicestests/test-apps/ConnTestApp/Android.bp services/tests/servicestests/test-apps/JobTestApp/Android.bp services/tests/servicestests/test-apps/PackageParserApp/Android.bp services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp services/tests/servicestests/test-apps/SuspendTestApp/Android.bp services/tests/shortcutmanagerutils/Android.bp services/tests/uiservicestests/Android.bp services/tests/wmtests/Android.bp services/usage/Android.bp services/usb/Android.bp services/voiceinteraction/Android.bp services/wifi/Android.bp startop/apps/test/Android.bp startop/iorap/Android.bp startop/iorap/functional_tests/Android.bp startop/iorap/stress/Android.bp startop/iorap/tests/Android.bp startop/view_compiler/Android.bp startop/view_compiler/dex_builder_test/Android.bp test-base/hiddenapi/Android.bp test-mock/Android.bp test-runner/tests/Android.bp tests/AccessibilityEventsLogger/Android.bp tests/AccessoryDisplay/common/Android.bp tests/AccessoryDisplay/sink/Android.bp tests/AccessoryDisplay/source/Android.bp tests/ActivityManagerPerfTests/stub-app/Android.bp tests/ActivityManagerPerfTests/test-app/Android.bp tests/ActivityManagerPerfTests/tests/Android.bp tests/ActivityManagerPerfTests/utils/Android.bp tests/ActivityTests/Android.bp tests/ActivityViewTest/Android.bp tests/AmSlam/Android.bp tests/ApkVerityTest/Android.bp tests/ApkVerityTest/ApkVerityTestApp/Android.bp tests/ApkVerityTest/block_device_writer/Android.bp tests/AppLaunch/Android.bp tests/AppLaunchWear/Android.bp tests/AppResourcesLoaders/Android.bp tests/AppResourcesLoaders/Overlay/Android.bp tests/Assist/Android.bp tests/AutoVerify/app1/Android.bp tests/AutoVerify/app2/Android.bp tests/AutoVerify/app3/Android.bp tests/AutoVerify/app4/Android.bp tests/BackgroundDexOptServiceIntegrationTests/Android.bp tests/BandwidthTests/Android.bp tests/BatteryWaster/Android.bp tests/BiDiTests/Android.bp tests/BlobStoreTestUtils/Android.bp tests/BootImageProfileTest/Android.bp tests/BrowserPowerTest/Android.bp tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp tests/CameraPrewarmTest/Android.bp tests/Codegen/Android.bp tests/Compatibility/Android.bp tests/CoreTests/android/Android.bp tests/DataIdleTest/Android.bp tests/DozeTest/Android.bp tests/DpiTest/Android.bp tests/DynamicCodeLoggerIntegrationTests/Android.mk tests/FeatureSplit/base/Android.bp tests/FeatureSplit/feature1/Android.bp tests/FeatureSplit/feature2/Android.bp tests/FixVibrateSetting/Android.bp tests/FlickerTests/Android.bp tests/FlickerTests/test-apps/Android.bp tests/FlickerTests/test-apps/flickerapp/Android.bp tests/FrameworkPerf/Android.bp tests/GamePerformance/Android.bp tests/GridLayoutTest/Android.bp tests/HierarchyViewerTest/Android.bp tests/HugeBackup/Android.bp tests/HwAccelerationTest/Android.bp tests/Internal/Android.bp tests/JankBench/Android.bp tests/JobSchedulerPerfTests/Android.bp tests/JobSchedulerTestApp/Android.bp tests/LargeAssetTest/Android.bp tests/LegacyAssistant/Android.bp tests/LocalizationTest/Android.bp tests/LocationTracker/Android.bp tests/LotsOfApps/Android.bp tests/LowStorageTest/Android.bp tests/ManagedProfileLifecycleStressTest/Android.bp tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp tests/MemoryUsage/Android.bp tests/MirrorSurfaceTest/Android.bp tests/NativeProcessesMemoryTest/Android.bp tests/NetworkSecurityConfigTest/Android.bp tests/NullHomeTest/Android.bp tests/OdmApps/Android.bp tests/OdmApps/app/Android.bp tests/OdmApps/priv-app/Android.bp tests/OneMedia/Android.bp tests/PackageWatchdog/Android.bp tests/PlatformCompatGating/Android.bp tests/PlatformCompatGating/test-rules/Android.bp tests/ProtoInputStreamTests/Android.bp tests/RemoteDisplayProvider/Android.bp tests/RenderThreadTest/Android.bp tests/RollbackTest/Android.bp tests/SerialChat/Android.bp tests/ServiceCrashTest/Android.bp tests/SharedLibrary/client/Android.bp tests/SharedLibrary/lib/Android.bp tests/ShowWhenLockedApp/Android.bp tests/SmokeTest/Android.bp tests/SmokeTest/tests/Android.bp tests/SmokeTestApps/Android.bp tests/SoundTriggerTestApp/Android.bp tests/Split/Android.bp tests/StagedInstallTest/Android.bp tests/StatusBar/Android.bp tests/SurfaceComposition/Android.bp tests/SurfaceControlViewHostTest/Android.bp tests/SystemMemoryTest/device/Android.bp tests/SystemMemoryTest/host/Android.bp tests/SystemUIDemoModeController/Android.bp tests/TaskOrganizerTest/Android.bp tests/TelephonyCommonTests/Android.bp tests/TouchLatency/Android.bp tests/TransformTest/Android.bp tests/TtsTests/Android.bp tests/UiBench/Android.bp tests/UsageReportingTest/Android.bp tests/UsageStatsPerfTests/Android.bp tests/UsageStatsTest/Android.bp tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp tests/UsbManagerTests/Android.bp tests/UsbManagerTests/lib/Android.bp tests/UsbTests/Android.bp tests/UsesFeature2Test/Android.bp tests/VectorDrawableTest/Android.bp tests/VoiceEnrollment/Android.bp tests/VoiceInteraction/Android.bp tests/WallpaperTest/Android.bp tests/WindowAnimationJank/Android.bp tests/WindowInsetsTests/Android.bp tests/appwidgets/AppWidgetHostTest/Android.bp tests/appwidgets/AppWidgetProviderTest/Android.bp tests/backup/Android.mk tests/benchmarks/Android.bp tests/libs-permissions/Android.bp tests/net/Android.bp tests/net/common/Android.bp tests/net/deflake/Android.bp tests/net/integration/Android.bp tests/net/jni/Android.bp tests/net/smoketest/Android.bp tests/notification/Android.bp tests/permission/Android.bp tests/privapp-permissions/Android.bp tests/testables/Android.bp tests/testables/tests/Android.bp tests/utils/StubIME/Android.bp tests/utils/hostutils/Android.bp tests/utils/testutils/Android.bp tests/vcn/Android.bp tools/aapt/Android.bp tools/aapt2/Android.bp tools/aapt2/integration-tests/AutoVersionTest/Android.bp tools/aapt2/integration-tests/BasicTest/Android.bp tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk tools/aapt2/integration-tests/StaticLibTest/App/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp tools/aapt2/integration-tests/SymlinkTest/Android.bp tools/bit/Android.bp tools/codegen/Android.bp tools/dump-coverage/Android.bp tools/incident_report/Android.bp tools/incident_section_gen/Android.bp tools/lock_agent/Android.bp tools/locked_region_code_injection/Android.bp tools/obbtool/Android.bp tools/powermodel/Android.bp tools/preload-check/Android.bp tools/preload-check/device/Android.bp tools/preload/loadclass/Android.bp tools/processors/staledataclass/Android.bp tools/processors/view_inspector/Android.bp tools/protologtool/Android.bp tools/sdkparcelables/Android.bp tools/split-select/Android.bp tools/streaming_proto/Android.bp tools/validatekeymaps/Android.bp wifi/java/Android.bp wifi/tests/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/hwui/Android.bp native/webview/plat_support/Android.bp obex/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-CPL-1.0 SPDX-license-identifier-GPL SPDX-license-identifier-GPL-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS SPDX-license-identifier-W3C legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD legacy_unencumbered to: core/java/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CPL-1.0 to: test-base/Android.bp test-runner/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL to: core/res/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL-2.0 to: libs/usb/Android.bp libs/usb/tests/accessorytest/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: tools/preload/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS to: api/Android.bp boot/Android.bp cmds/device_config/Android.bp cmds/settings/Android.bp core/api/Android.bp core/tests/coretests/certs/Android.bp core/tests/overlaytests/remount/test-apps/certs/Android.bp core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp libs/tracingproxy/Android.bp services/startop/Android.bp test-legacy/Android.mk tests/ApkVerityTest/testdata/Android.bp tests/TransitionTests/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ic44d662936d1ff0cae7fbe915932b37aa4e4869a Merged-in: I6e9103c3275cb2e6df5dc586588eccd7d2ab6b06 --- Vcn/service-b/src/com/android/server/vcn/Android.bp | 11 ++++++++++- Vcn/tests/unit/Android.bp | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp index 5ed204fd76..ab5da3ee45 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Android.bp +++ b/Vcn/service-b/src/com/android/server/vcn/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "framework-vcn-util-sources", srcs: ["util/**/*.java"], -} \ No newline at end of file +} diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index c04ddd78e6..345c2a9f30 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -2,6 +2,15 @@ // Build FrameworksVcnTests package //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "FrameworksVcnTests", srcs: [ From f5c74807c4e4c5abe3b5875a2c9833a5359f65c5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 4 Feb 2021 23:02:28 -0800 Subject: [PATCH 0065/1057] Implement Safemode alarm in VcnGatewayConnection. This CL updates VcnGatewayConnection to use WakeupMessages to support Safemode detection. Safemode is entered if the VcnGatewayConnection instance takes more than SAFEMODE_TIMEOUT_SECONDS seconds to a) go from DisconnectedState to ConnectedState, or b) exit and re-enter ConnectedState. If this timeout is exceeded, the instance will notify its managing Vcn via VcnGatewayStatusCallback#onEnteredSafemode. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: Iff40aba639b465c3959ef383f1001be419daba4d --- .../server/vcn/VcnGatewayConnection.java | 108 +++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 29 ++++- ...nGatewayConnectionConnectingStateTest.java | 5 + ...atewayConnectionDisconnectedStateTest.java | 5 +- ...tewayConnectionDisconnectingStateTest.java | 5 + ...atewayConnectionRetryTimeoutStateTest.java | 5 + .../vcn/VcnGatewayConnectionTestBase.java | 25 ++++ 7 files changed, 176 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8aab3a66ad..0ed26dbe83 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -38,10 +38,12 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkAgent.ValidationStatus; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; @@ -151,6 +153,9 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static final String RETRY_TIMEOUT_ALARM = TAG + "_RETRY_TIMEOUT_ALARM"; + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String SAFEMODE_TIMEOUT_ALARM = TAG + "_SAFEMODE_TIMEOUT_ALARM"; + private static final int[] MERGED_CAPABILITIES = new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING}; private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE; @@ -167,6 +172,9 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int TEARDOWN_TIMEOUT_SECONDS = 5; + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int SAFEMODE_TIMEOUT_SECONDS = 30; + private interface EventInfo {} /** @@ -409,6 +417,23 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/178426520): implement handling of this event private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9; + /** + * Sent when this VcnGatewayConnection has entered Safemode. + * + *

    A VcnGatewayConnection enters Safemode when it takes over {@link + * #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}. + * + *

    When a VcnGatewayConnection enters safe mode, it will fire {@link + * VcnGatewayStatusCallback#onEnteredSafemode()} to notify its Vcn. The Vcn will then shut down + * its VcnGatewayConnectin(s). + * + *

    Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not + * validated yet), and RetryTimeoutState. + * + * @param arg1 The "all" token; this signal is always honored. + */ + private static final int EVENT_SAFEMODE_TIMEOUT_EXCEEDED = 10; + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -520,11 +545,13 @@ public class VcnGatewayConnection extends StateMachine { *

    Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable * otherwise. */ - private NetworkAgent mNetworkAgent; + @VisibleForTesting(visibility = Visibility.PRIVATE) + NetworkAgent mNetworkAgent; @Nullable private WakeupMessage mTeardownTimeoutAlarm; @Nullable private WakeupMessage mDisconnectRequestAlarm; @Nullable private WakeupMessage mRetryTimeoutAlarm; + @Nullable private WakeupMessage mSafemodeTimeoutAlarm; public VcnGatewayConnection( @NonNull VcnContext vcnContext, @@ -611,6 +638,7 @@ public class VcnGatewayConnection extends StateMachine { cancelTeardownTimeoutAlarm(); cancelDisconnectRequestAlarm(); cancelRetryTimeoutAlarm(); + cancelSafemodeAlarm(); mUnderlyingNetworkTracker.teardown(); } @@ -899,6 +927,30 @@ public class VcnGatewayConnection extends StateMachine { removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setSafemodeAlarm() { + // Only schedule a NEW alarm if none is already set. + if (mSafemodeTimeoutAlarm != null) { + return; + } + + final Message delayedMessage = obtainMessage(EVENT_SAFEMODE_TIMEOUT_EXCEEDED, TOKEN_ALL); + mSafemodeTimeoutAlarm = + createScheduledAlarm( + SAFEMODE_TIMEOUT_ALARM, + delayedMessage, + TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + } + + private void cancelSafemodeAlarm() { + if (mSafemodeTimeoutAlarm != null) { + mSafemodeTimeoutAlarm.cancel(); + mSafemodeTimeoutAlarm = null; + } + + removeEqualMessages(EVENT_SAFEMODE_TIMEOUT_EXCEEDED); + } + private void sessionLost(int token, @Nullable Exception exception) { sendMessageAndAcquireWakeLock( EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); @@ -1072,6 +1124,8 @@ public class VcnGatewayConnection extends StateMachine { if (mIkeSession != null || mNetworkAgent != null) { Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); } + + cancelSafemodeAlarm(); } @Override @@ -1095,6 +1149,12 @@ public class VcnGatewayConnection extends StateMachine { break; } } + + @Override + protected void exitState() { + // Safe to blindly set up, as it is cancelled and cleared on entering this state + setSafemodeAlarm(); + } } private abstract class ActiveBaseState extends BaseState { @@ -1185,6 +1245,10 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mDisconnectedState); } break; + case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafemode(); + mSafemodeTimeoutAlarm = null; + break; default: logUnhandledMessage(msg); break; @@ -1267,6 +1331,10 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; + case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafemode(); + mSafemodeTimeoutAlarm = null; + break; default: logUnhandledMessage(msg); break; @@ -1310,6 +1378,14 @@ public class VcnGatewayConnection extends StateMachine { public void unwanted() { teardownAsynchronously(); } + + @Override + public void onValidationStatus( + @ValidationStatus int status, @Nullable Uri redirectUri) { + if (status == NetworkAgent.VALIDATION_STATUS_VALID) { + clearFailedAttemptCounterAndSafeModeAlarm(); + } + } }; agent.register(); @@ -1318,6 +1394,14 @@ public class VcnGatewayConnection extends StateMachine { return agent; } + protected void clearFailedAttemptCounterAndSafeModeAlarm() { + mVcnContext.ensureRunningOnLooperThread(); + + // Validated connection, clear failed attempt counter + mFailedAttempts = 0; + cancelSafemodeAlarm(); + } + protected void applyTransform( int token, @NonNull IpSecTunnelInterface tunnelIface, @@ -1397,9 +1481,6 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } } - - // Successful connection, clear failed attempt counter - mFailedAttempts = 0; } @Override @@ -1436,6 +1517,10 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; + case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafemode(); + mSafemodeTimeoutAlarm = null; + break; default: logUnhandledMessage(msg); break; @@ -1478,8 +1563,19 @@ public class VcnGatewayConnection extends StateMachine { mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig); } else { updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig); + + // mNetworkAgent not null, so the VCN Network has already been established. Clear + // the failed attempt counter and safe mode alarm since this transition is complete. + clearFailedAttemptCounterAndSafeModeAlarm(); } } + + @Override + protected void exitState() { + // Attempt to set the safe mode alarm - this requires the Vcn Network being validated + // while in ConnectedState (which cancels the previous alarm) + setSafemodeAlarm(); + } } /** @@ -1526,6 +1622,10 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; + case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafemode(); + mSafemodeTimeoutAlarm = null; + break; default: logUnhandledMessage(msg); break; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index faa8b234cf..a6eae96100 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -34,8 +34,10 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import android.net.LinkProperties; +import android.net.NetworkAgent; import android.net.NetworkCapabilities; import androidx.test.filters.SmallTest; @@ -72,6 +74,11 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mDeps).newIkeSession(any(), any(), any(), any(), any()); } + @Test + public void testEnterStateDoesNotCancelSafemodeAlarm() { + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + } + @Test public void testNullNetworkDoesNotTriggerDisconnect() throws Exception { mGatewayConnection @@ -122,6 +129,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testChildOpenedRegistersNetwork() throws Exception { + // Verify scheduled but not canceled when entering ConnectedState + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + final VcnChildSessionConfiguration mMockChildSessionConfig = mock(VcnChildSessionConfiguration.class); doReturn(Collections.singletonList(TEST_INTERNAL_ADDR)) @@ -163,24 +173,41 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection for (int cap : mConfig.getAllExposedCapabilities()) { assertTrue(nc.hasCapability(cap)); } + + // Now that Vcn Network is up, notify it as validated and verify the Safemode alarm is + // canceled + mGatewayConnection.mNetworkAgent.onValidationStatus( + NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */); + verify(mSafemodeTimeoutAlarm).cancel(); } @Test public void testChildSessionClosedTriggersDisconnect() throws Exception { + // Verify scheduled but not canceled when entering ConnectedState + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + getChildSessionCallback().onClosed(); mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); + + // Since network never validated, verify mSafemodeTimeoutAlarm not canceled + verifyNoMoreInteractions(mSafemodeTimeoutAlarm); } @Test public void testIkeSessionClosedTriggersDisconnect() throws Exception { + // Verify scheduled but not canceled when entering ConnectedState + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + getIkeSessionCallback().onClosed(); mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); - verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */); + + // Since network never validated, verify mSafemodeTimeoutAlarm not canceled + verifyNoMoreInteractions(mSafemodeTimeoutAlarm); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 760379d664..07282c9200 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -106,4 +106,9 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio verify(mIkeSession).close(); verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */); } + + @Test + public void testSafemodeTimeoutNotifiesCallback() { + verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 1a1787ac19..49ce54d4f6 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -48,7 +48,8 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect .createIpSecTunnelInterface( DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); mGatewayConnection.setTunnelInterface(tunnelIface); - mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState); + + // Don't need to transition to DisconnectedState because it is the starting state mTestLooper.dispatchAll(); } @@ -78,6 +79,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -98,5 +100,6 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); + verifySafemodeTimeoutAlarmAndGetCallback(true /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index b09f3a008c..22eab2a1aa 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -80,4 +80,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); } + + @Test + public void testSafemodeTimeoutNotifiesCallback() { + verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index d37e92f661..6c26075866 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -91,4 +91,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); } + + @Test + public void testSafemodeTimeoutNotifiesCallback() { + verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 0b44e03a5e..ac9ec0663d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -20,6 +20,7 @@ import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkR import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; @@ -50,6 +51,7 @@ import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import com.android.internal.util.State; import com.android.internal.util.WakeupMessage; import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -108,6 +110,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final WakeupMessage mTeardownTimeoutAlarm; @NonNull protected final WakeupMessage mDisconnectRequestAlarm; @NonNull protected final WakeupMessage mRetryTimeoutAlarm; + @NonNull protected final WakeupMessage mSafemodeTimeoutAlarm; @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; @@ -128,6 +131,7 @@ public class VcnGatewayConnectionTestBase { mTeardownTimeoutAlarm = mock(WakeupMessage.class); mDisconnectRequestAlarm = mock(WakeupMessage.class); mRetryTimeoutAlarm = mock(WakeupMessage.class); + mSafemodeTimeoutAlarm = mock(WakeupMessage.class); mIpSecSvc = mock(IpSecService.class); setupIpSecManager(mContext, mIpSecSvc); @@ -150,6 +154,7 @@ public class VcnGatewayConnectionTestBase { setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM); setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM); setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM); + setUpWakeupMessage(mSafemodeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM); doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime(); } @@ -253,4 +258,24 @@ public class VcnGatewayConnectionTestBase { delayInMillis, expectCanceled); } + + protected Runnable verifySafemodeTimeoutAlarmAndGetCallback(boolean expectCanceled) { + return verifyWakeupMessageSetUpAndGetCallback( + VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, + mSafemodeTimeoutAlarm, + TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS), + expectCanceled); + } + + protected void verifySafemodeTimeoutNotifiesCallback(@NonNull State expectedState) { + // Safemode timer starts when VcnGatewayConnection exits DisconnectedState (the initial + // state) + final Runnable delayedEvent = + verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + delayedEvent.run(); + mTestLooper.dispatchAll(); + + verify(mGatewayStatusCallback).onEnteredSafemode(); + assertEquals(expectedState, mGatewayConnection.getCurrentState()); + } } From 67578f56dec97f7a697208e3294571267744dfaa Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 12 Feb 2021 23:31:10 -0800 Subject: [PATCH 0066/1057] Implement ChildSessionCallback#onIpSecTransformsMigrated This change implements the Migrated callback, proxying to onIpSecTransformCreated Bug: 180163196 Test: atest FrameworksVcnTests Change-Id: Ibf07be667882ea35a4d7191b87d1193f38f9db3e --- .../android/server/vcn/VcnGatewayConnection.java | 12 +++++++++++- .../VcnGatewayConnectionConnectedStateTest.java | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8aab3a66ad..db897f3d3e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1325,7 +1325,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform transform, int direction) { try { - // TODO: Set underlying network of tunnel interface + // TODO(b/180163196): Set underlying network of tunnel interface // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); @@ -1455,6 +1455,7 @@ public class VcnGatewayConnection extends StateMachine { // mUnderlying assumed non-null, given check above. // If network changed, migrate. Otherwise, update any existing networkAgent. if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) { + Slog.v(TAG, "Migrating to new network: " + mUnderlying.network); mIkeSession.setNetwork(mUnderlying.network); } else { // oldUnderlying is non-null & underlying network itself has not changed @@ -1707,6 +1708,15 @@ public class VcnGatewayConnection extends StateMachine { childTransformCreated(mToken, transform, direction); } + @Override + public void onIpSecTransformsMigrated( + @NonNull IpSecTransform inIpSecTransform, + @NonNull IpSecTransform outIpSecTransform) { + Slog.v(TAG, "ChildTransformsMigrated; token " + mToken); + onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN); + onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT); + } + @Override public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) { // Nothing to be done; no references to the IpSecTransform are held, and this transform diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index faa8b234cf..730192e170 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -120,6 +120,20 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } + @Test + public void testMigratedTransformsAreApplied() throws Exception { + getChildSessionCallback() + .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); + mTestLooper.dispatchAll(); + + for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { + verify(mIpSecSvc) + .applyTunnelModeTransform( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); + } + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + } + @Test public void testChildOpenedRegistersNetwork() throws Exception { final VcnChildSessionConfiguration mMockChildSessionConfig = From f169f04bf403864f98ee5896916c566c32fecae3 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 19:42:55 -0800 Subject: [PATCH 0067/1057] [LSC] Add LOCAL_LICENSE_KINDS to cts Added SPDX-license-identifier-Apache-2.0 to: apps/CrossProfileTestApp/Android.bp apps/CtsVerifier/jni/audio_loopback/Android.bp apps/CtsVerifier/jni/midi/Android.bp apps/CtsVerifier/jni/verifier/Android.bp apps/CtsVerifierInstantApp/Android.bp apps/CtsVerifierUSBCompanion/Android.bp apps/EmptyDeviceAdmin/Android.bp apps/EmptyDeviceOwner/Android.bp apps/ForceStopHelperApp/Android.bp apps/NotificationBot/Android.bp apps/OomCatcher/Android.bp apps/PermissionApp/Android.bp apps/VpnApp/Android.bp common/device-side/device-info/Android.bp common/device-side/device-info/tests/Android.bp common/device-side/nativetesthelper/Android.bp common/device-side/nativetesthelper/jni/Android.bp common/device-side/preconditions/Android.bp common/device-side/test-app/Android.bp common/device-side/util-axt/Android.bp common/device-side/util-axt/tests/Android.bp common/device-side/util/jni/Android.bp common/host-side/util-axt/Android.bp helpers/default/Android.bp hostsidetests/abioverride/Android.bp hostsidetests/abioverride/app/Android.bp hostsidetests/abioverride/app/jni/Android.bp hostsidetests/accounts/Android.bp hostsidetests/accounts/test-apps/AccountManagerCrossUserApp/Android.bp hostsidetests/adb/Android.mk hostsidetests/adbmanager/Android.bp hostsidetests/angle/Android.bp hostsidetests/angle/app/common/Android.bp hostsidetests/angle/app/driverTest/Android.bp hostsidetests/angle/app/driverTestSecondary/Android.bp hostsidetests/apex/Android.bp hostsidetests/appbinding/app/Android.bp hostsidetests/appbinding/hostside/Android.bp hostsidetests/appcompat/compatchanges/Android.bp hostsidetests/appcompat/compatchanges/app/Android.bp hostsidetests/appcompat/compatchanges/preInstallOverrideApps/Android.bp hostsidetests/appcompat/host/lib/Android.bp hostsidetests/appcompat/strictjavapackages/Android.bp hostsidetests/appsecurity/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppAccessData/Android.bp hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppWithData/Android.bp hostsidetests/appsecurity/test-apps/ApplicationVisibilityCrossUserApp/Android.bp hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/compressed_arsc/Android.bp hostsidetests/appsecurity/test-apps/DeviceIdentifiers/Android.bp hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/EncryptionApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.bp hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.bp hostsidetests/appsecurity/test-apps/InstantUpgradeApp/Android.bp hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.bp hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk hostsidetests/appsecurity/test-apps/ListeningPortsApp/Android.bp hostsidetests/appsecurity/test-apps/LocationPolicyApp/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000000000ffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version00000000ffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ff00000000/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ffffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/src-common/Android.bp hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.bp hostsidetests/appsecurity/test-apps/OrderedActivityApp/Android.bp hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk hostsidetests/appsecurity/test-apps/StorageApp/Android.bp hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.bp hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.bp hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailActivity/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailApplication/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailProvider/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailReceiver/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailService/Android.bp hostsidetests/appsecurity/test-apps/UseProcessSuccess/Android.bp hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.bp hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permUse/Android.bp hostsidetests/appsecurity/test-apps/keysets/testApp/Android.bp hostsidetests/appsecurity/test-apps/keysets/uA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.bp hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uNone/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAll/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAndroid/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayApp/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyProduct/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySignatureDifferent/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySystem/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyVendor/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayTarget/Android.bp hostsidetests/appsecurity/test-apps/stubime/Android.bp hostsidetests/atrace/Android.bp hostsidetests/atrace/AtraceTestApp/Android.bp hostsidetests/atrace/AtraceTestApp/jni/Android.bp hostsidetests/backup/AllowBackup/Android.bp hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.bp hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.bp hostsidetests/backup/Android.bp hostsidetests/backup/AutoRestoreApp/Android.bp hostsidetests/backup/BackupTransportApp/Android.bp hostsidetests/backup/FullBackupOnly/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.bp hostsidetests/backup/KeyValueApp/Android.bp hostsidetests/backup/OtherSoundsSettingsApp/Android.bp hostsidetests/backup/PreservedSettingsApp/Android.bp hostsidetests/backup/ProfileFullBackupApp/Android.bp hostsidetests/backup/ProfileKeyValueApp/Android.bp hostsidetests/backup/ProfileSerialNumberApp/Android.bp hostsidetests/backup/RestoreAnyVersion/Android.bp hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreSessionTest/Android.bp hostsidetests/backup/SharedPreferencesRestoreApp/Android.bp hostsidetests/backup/SuccessNotificationApp/Android.bp hostsidetests/backup/SyncAdapterSettingsApp/Android.bp hostsidetests/backup/fullbackupapp/Android.bp hostsidetests/backup/includeexcludeapp/Android.bp hostsidetests/backup/restoresessionapp1/Android.bp hostsidetests/backup/restoresessionapp2/Android.bp hostsidetests/backup/restoresessionapp3/Android.bp hostsidetests/blobstore/Android.bp hostsidetests/bootstats/Android.bp hostsidetests/car/Android.bp hostsidetests/classloaders/splits/Android.bp hostsidetests/classloaders/splits/apps/Android.bp hostsidetests/classloaders/splits/apps/feature_a/Android.bp hostsidetests/classloaders/splits/apps/feature_b/Android.bp hostsidetests/classloaders/useslibrary/Android.bp hostsidetests/classloaders/useslibrary/app/Android.bp hostsidetests/compilation/Android.bp hostsidetests/compilation/app/Android.bp hostsidetests/content/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileApp/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileTestServiceApp/Android.bp hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp hostsidetests/cpptools/Android.bp hostsidetests/cpptools/test-apps/BasicApp/Android.bp hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp hostsidetests/deviceidle/Android.bp hostsidetests/devicepolicy/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp hostsidetests/devicepolicy/app/AccountManagement/Android.bp hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp hostsidetests/devicepolicy/app/Assistant/Android.bp hostsidetests/devicepolicy/app/AutofillApp/Android.bp hostsidetests/devicepolicy/app/CertInstaller/Android.bp hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp hostsidetests/devicepolicy/app/CustomizationApp/Android.bp hostsidetests/devicepolicy/app/DelegateApp/Android.bp hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp hostsidetests/devicepolicy/app/DeviceOwner/Android.bp hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp hostsidetests/devicepolicy/app/IntentReceiver/Android.bp hostsidetests/devicepolicy/app/IntentSender/Android.bp hostsidetests/devicepolicy/app/LauncherTests/Android.bp hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp hostsidetests/devicepolicy/app/ManagedProfile/Android.bp hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp hostsidetests/devicepolicy/app/NotificationSender/Android.bp hostsidetests/devicepolicy/app/PackageInstaller/Android.bp hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp hostsidetests/devicepolicy/app/PrintingApp/Android.bp hostsidetests/devicepolicy/app/ProfileOwner/Android.bp hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp hostsidetests/devicepolicy/app/SharingApps/Android.bp hostsidetests/devicepolicy/app/SimpleApp/Android.bp hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp hostsidetests/devicepolicy/app/SuspensionChecker/Android.bp hostsidetests/devicepolicy/app/TestApps/Android.bp hostsidetests/devicepolicy/app/TestIme/Android.bp hostsidetests/devicepolicy/app/TestLauncher/Android.bp hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp hostsidetests/devicepolicy/app/WidgetProvider/Android.bp hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp hostsidetests/dexmetadata/app/Android.bp hostsidetests/dexmetadata/app/SplitApp/Android.bp hostsidetests/dexmetadata/app/SplitApp/SplitAppFeatureA/Android.bp hostsidetests/dexmetadata/host/Android.bp hostsidetests/dumpsys/Android.bp hostsidetests/dumpsys/apps/FramestatsTestApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.bp hostsidetests/dumpsys/apps/storagedapp/Android.bp hostsidetests/edi/Android.bp hostsidetests/gputools/apps/Android.bp hostsidetests/graphics/gpuprofiling/Android.bp hostsidetests/graphics/gpuprofiling/app/Android.bp hostsidetests/harmfulappwarning/Android.bp hostsidetests/harmfulappwarning/sampleapp/Android.bp hostsidetests/harmfulappwarning/testapp/Android.bp hostsidetests/hdmicec/Android.bp hostsidetests/hdmicec/app/Android.bp hostsidetests/incident/Android.bp hostsidetests/incident/apps/batterystatsapp/Android.bp hostsidetests/incident/apps/boundwidgetapp/Android.bp hostsidetests/incident/apps/errorsapp/Android.bp hostsidetests/incident/apps/errorsapp/jni/Android.bp hostsidetests/incident/apps/graphicsstatsapp/Android.bp hostsidetests/incident/apps/notificationsapp/Android.bp hostsidetests/incident/apps/procstatsapp/Android.bp hostsidetests/incrementalinstall/Android.bp hostsidetests/incrementalinstall/app/Android.bp hostsidetests/incrementalinstall/app/dynamicasset/Android.bp hostsidetests/incrementalinstall/app/dynamiccode/Android.bp hostsidetests/incrementalinstall/app/nativelibcompressed/Android.bp hostsidetests/incrementalinstall/app/nativelibuncompressed/Android.bp hostsidetests/incrementalinstall/appvalidator/Android.bp hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/jni/Android.bp hostsidetests/incrementalinstall/common/Android.bp hostsidetests/inputmethodservice/common/Android.bp hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp hostsidetests/inputmethodservice/deviceside/ime1/Android.bp hostsidetests/inputmethodservice/deviceside/ime2/Android.bp hostsidetests/inputmethodservice/deviceside/lib/Android.bp hostsidetests/inputmethodservice/deviceside/provider/Android.bp hostsidetests/inputmethodservice/hostside/Android.bp hostsidetests/jdwpsecurity/Android.bp hostsidetests/jdwpsecurity/app/Android.bp hostsidetests/jdwptunnel/Android.bp hostsidetests/jdwptunnel/sampleapps/ddmsapp/Android.bp hostsidetests/jdwptunnel/sampleapps/debuggableapp/Android.bp hostsidetests/jdwptunnel/sampleapps/profileableapp/Android.bp hostsidetests/jvmti/allocation-tracking/Android.bp hostsidetests/jvmti/allocation-tracking/app/Android.bp hostsidetests/jvmti/attaching/Android.bp hostsidetests/jvmti/base/app/Android.bp hostsidetests/jvmti/base/host/Android.bp hostsidetests/jvmti/base/jni/Android.bp hostsidetests/jvmti/base/run-test-based-app/Android.bp hostsidetests/jvmti/redefining/Android.bp hostsidetests/jvmti/redefining/app/Android.bp hostsidetests/jvmti/run-tests/Android.bp hostsidetests/jvmti/run-tests/test-1900/Android.bp hostsidetests/jvmti/run-tests/test-1900/app/Android.bp hostsidetests/jvmti/run-tests/test-1901/Android.bp hostsidetests/jvmti/run-tests/test-1901/app/Android.bp hostsidetests/jvmti/run-tests/test-1902/Android.bp hostsidetests/jvmti/run-tests/test-1902/app/Android.bp hostsidetests/jvmti/run-tests/test-1903/Android.bp hostsidetests/jvmti/run-tests/test-1903/app/Android.bp hostsidetests/jvmti/run-tests/test-1904/Android.bp hostsidetests/jvmti/run-tests/test-1904/app/Android.bp hostsidetests/jvmti/run-tests/test-1906/Android.bp hostsidetests/jvmti/run-tests/test-1906/app/Android.bp hostsidetests/jvmti/run-tests/test-1907/Android.bp hostsidetests/jvmti/run-tests/test-1907/app/Android.bp hostsidetests/jvmti/run-tests/test-1908/Android.bp hostsidetests/jvmti/run-tests/test-1908/app/Android.bp hostsidetests/jvmti/run-tests/test-1909/Android.bp hostsidetests/jvmti/run-tests/test-1909/app/Android.bp hostsidetests/jvmti/run-tests/test-1910/Android.bp hostsidetests/jvmti/run-tests/test-1910/app/Android.bp hostsidetests/jvmti/run-tests/test-1911/Android.bp hostsidetests/jvmti/run-tests/test-1911/app/Android.bp hostsidetests/jvmti/run-tests/test-1912/Android.bp hostsidetests/jvmti/run-tests/test-1912/app/Android.bp hostsidetests/jvmti/run-tests/test-1913/Android.bp hostsidetests/jvmti/run-tests/test-1913/app/Android.bp hostsidetests/jvmti/run-tests/test-1914/Android.bp hostsidetests/jvmti/run-tests/test-1914/app/Android.bp hostsidetests/jvmti/run-tests/test-1915/Android.bp hostsidetests/jvmti/run-tests/test-1915/app/Android.bp hostsidetests/jvmti/run-tests/test-1916/Android.bp hostsidetests/jvmti/run-tests/test-1916/app/Android.bp hostsidetests/jvmti/run-tests/test-1917/Android.bp hostsidetests/jvmti/run-tests/test-1917/app/Android.bp hostsidetests/jvmti/run-tests/test-1920/Android.bp hostsidetests/jvmti/run-tests/test-1920/app/Android.bp hostsidetests/jvmti/run-tests/test-1921/Android.bp hostsidetests/jvmti/run-tests/test-1921/app/Android.bp hostsidetests/jvmti/run-tests/test-1922/Android.bp hostsidetests/jvmti/run-tests/test-1922/app/Android.bp hostsidetests/jvmti/run-tests/test-1923/Android.bp hostsidetests/jvmti/run-tests/test-1923/app/Android.bp hostsidetests/jvmti/run-tests/test-1924/Android.bp hostsidetests/jvmti/run-tests/test-1924/app/Android.bp hostsidetests/jvmti/run-tests/test-1925/Android.bp hostsidetests/jvmti/run-tests/test-1925/app/Android.bp hostsidetests/jvmti/run-tests/test-1926/Android.bp hostsidetests/jvmti/run-tests/test-1926/app/Android.bp hostsidetests/jvmti/run-tests/test-1927/Android.bp hostsidetests/jvmti/run-tests/test-1927/app/Android.bp hostsidetests/jvmti/run-tests/test-1928/Android.bp hostsidetests/jvmti/run-tests/test-1928/app/Android.bp hostsidetests/jvmti/run-tests/test-1930/Android.bp hostsidetests/jvmti/run-tests/test-1930/app/Android.bp hostsidetests/jvmti/run-tests/test-1931/Android.bp hostsidetests/jvmti/run-tests/test-1931/app/Android.bp hostsidetests/jvmti/run-tests/test-1932/Android.bp hostsidetests/jvmti/run-tests/test-1932/app/Android.bp hostsidetests/jvmti/run-tests/test-1933/Android.bp hostsidetests/jvmti/run-tests/test-1933/app/Android.bp hostsidetests/jvmti/run-tests/test-1934/Android.bp hostsidetests/jvmti/run-tests/test-1934/app/Android.bp hostsidetests/jvmti/run-tests/test-1936/Android.bp hostsidetests/jvmti/run-tests/test-1936/app/Android.bp hostsidetests/jvmti/run-tests/test-1937/Android.bp hostsidetests/jvmti/run-tests/test-1937/app/Android.bp hostsidetests/jvmti/run-tests/test-1939/Android.bp hostsidetests/jvmti/run-tests/test-1939/app/Android.bp hostsidetests/jvmti/run-tests/test-1941/Android.bp hostsidetests/jvmti/run-tests/test-1941/app/Android.bp hostsidetests/jvmti/run-tests/test-1942/Android.bp hostsidetests/jvmti/run-tests/test-1942/app/Android.bp hostsidetests/jvmti/run-tests/test-1943/Android.bp hostsidetests/jvmti/run-tests/test-1943/app/Android.bp hostsidetests/jvmti/run-tests/test-1953/Android.bp hostsidetests/jvmti/run-tests/test-1953/app/Android.bp hostsidetests/jvmti/run-tests/test-1958/Android.bp hostsidetests/jvmti/run-tests/test-1958/app/Android.bp hostsidetests/jvmti/run-tests/test-1962/Android.bp hostsidetests/jvmti/run-tests/test-1962/app/Android.bp hostsidetests/jvmti/run-tests/test-1967/Android.bp hostsidetests/jvmti/run-tests/test-1967/app/Android.bp hostsidetests/jvmti/run-tests/test-1968/Android.bp hostsidetests/jvmti/run-tests/test-1968/app/Android.bp hostsidetests/jvmti/run-tests/test-1969/Android.bp hostsidetests/jvmti/run-tests/test-1969/app/Android.bp hostsidetests/jvmti/run-tests/test-1970/Android.bp hostsidetests/jvmti/run-tests/test-1970/app/Android.bp hostsidetests/jvmti/run-tests/test-1971/Android.bp hostsidetests/jvmti/run-tests/test-1971/app/Android.bp hostsidetests/jvmti/run-tests/test-1974/Android.bp hostsidetests/jvmti/run-tests/test-1974/app/Android.bp hostsidetests/jvmti/run-tests/test-1975/Android.bp hostsidetests/jvmti/run-tests/test-1975/app/Android.bp hostsidetests/jvmti/run-tests/test-1976/Android.bp hostsidetests/jvmti/run-tests/test-1976/app/Android.bp hostsidetests/jvmti/run-tests/test-1977/Android.bp hostsidetests/jvmti/run-tests/test-1977/app/Android.bp hostsidetests/jvmti/run-tests/test-1978/Android.bp hostsidetests/jvmti/run-tests/test-1978/app/Android.bp hostsidetests/jvmti/run-tests/test-1979/Android.bp hostsidetests/jvmti/run-tests/test-1979/app/Android.bp hostsidetests/jvmti/run-tests/test-1981/Android.bp hostsidetests/jvmti/run-tests/test-1981/app/Android.bp hostsidetests/jvmti/run-tests/test-1982/Android.bp hostsidetests/jvmti/run-tests/test-1982/app/Android.bp hostsidetests/jvmti/run-tests/test-1983/Android.bp hostsidetests/jvmti/run-tests/test-1983/app/Android.bp hostsidetests/jvmti/run-tests/test-1984/Android.bp hostsidetests/jvmti/run-tests/test-1984/app/Android.bp hostsidetests/jvmti/run-tests/test-1988/Android.bp hostsidetests/jvmti/run-tests/test-1988/app/Android.bp hostsidetests/jvmti/run-tests/test-1989/Android.bp hostsidetests/jvmti/run-tests/test-1989/app/Android.bp hostsidetests/jvmti/run-tests/test-1990/Android.bp hostsidetests/jvmti/run-tests/test-1990/app/Android.bp hostsidetests/jvmti/run-tests/test-1991/Android.bp hostsidetests/jvmti/run-tests/test-1991/app/Android.bp hostsidetests/jvmti/run-tests/test-1992/Android.bp hostsidetests/jvmti/run-tests/test-1992/app/Android.bp hostsidetests/jvmti/run-tests/test-1994/Android.bp hostsidetests/jvmti/run-tests/test-1994/app/Android.bp hostsidetests/jvmti/run-tests/test-1995/Android.bp hostsidetests/jvmti/run-tests/test-1995/app/Android.bp hostsidetests/jvmti/run-tests/test-1996/Android.bp hostsidetests/jvmti/run-tests/test-1996/app/Android.bp hostsidetests/jvmti/run-tests/test-1997/Android.bp hostsidetests/jvmti/run-tests/test-1997/app/Android.bp hostsidetests/jvmti/run-tests/test-1998/Android.bp hostsidetests/jvmti/run-tests/test-1998/app/Android.bp hostsidetests/jvmti/run-tests/test-1999/Android.bp hostsidetests/jvmti/run-tests/test-1999/app/Android.bp hostsidetests/jvmti/run-tests/test-2001/Android.bp hostsidetests/jvmti/run-tests/test-2001/app/Android.bp hostsidetests/jvmti/run-tests/test-2002/Android.bp hostsidetests/jvmti/run-tests/test-2002/app/Android.bp hostsidetests/jvmti/run-tests/test-2003/Android.bp hostsidetests/jvmti/run-tests/test-2003/app/Android.bp hostsidetests/jvmti/run-tests/test-2004/Android.bp hostsidetests/jvmti/run-tests/test-2004/app/Android.bp hostsidetests/jvmti/run-tests/test-2005/Android.bp hostsidetests/jvmti/run-tests/test-2005/app/Android.bp hostsidetests/jvmti/run-tests/test-2006/Android.bp hostsidetests/jvmti/run-tests/test-2006/app/Android.bp hostsidetests/jvmti/run-tests/test-2007/Android.bp hostsidetests/jvmti/run-tests/test-2007/app/Android.bp hostsidetests/jvmti/run-tests/test-902/Android.bp hostsidetests/jvmti/run-tests/test-902/app/Android.bp hostsidetests/jvmti/run-tests/test-903/Android.bp hostsidetests/jvmti/run-tests/test-903/app/Android.bp hostsidetests/jvmti/run-tests/test-904/Android.bp hostsidetests/jvmti/run-tests/test-904/app/Android.bp hostsidetests/jvmti/run-tests/test-905/Android.bp hostsidetests/jvmti/run-tests/test-905/app/Android.bp hostsidetests/jvmti/run-tests/test-906/Android.bp hostsidetests/jvmti/run-tests/test-906/app/Android.bp hostsidetests/jvmti/run-tests/test-907/Android.bp hostsidetests/jvmti/run-tests/test-907/app/Android.bp hostsidetests/jvmti/run-tests/test-908/Android.bp hostsidetests/jvmti/run-tests/test-908/app/Android.bp hostsidetests/jvmti/run-tests/test-910/Android.bp hostsidetests/jvmti/run-tests/test-910/app/Android.bp hostsidetests/jvmti/run-tests/test-911/Android.bp hostsidetests/jvmti/run-tests/test-911/app/Android.bp hostsidetests/jvmti/run-tests/test-912/Android.bp hostsidetests/jvmti/run-tests/test-912/app/Android.bp hostsidetests/jvmti/run-tests/test-913/Android.bp hostsidetests/jvmti/run-tests/test-913/app/Android.bp hostsidetests/jvmti/run-tests/test-914/Android.bp hostsidetests/jvmti/run-tests/test-914/app/Android.bp hostsidetests/jvmti/run-tests/test-915/Android.bp hostsidetests/jvmti/run-tests/test-915/app/Android.bp hostsidetests/jvmti/run-tests/test-917/Android.bp hostsidetests/jvmti/run-tests/test-917/app/Android.bp hostsidetests/jvmti/run-tests/test-918/Android.bp hostsidetests/jvmti/run-tests/test-918/app/Android.bp hostsidetests/jvmti/run-tests/test-919/Android.bp hostsidetests/jvmti/run-tests/test-919/app/Android.bp hostsidetests/jvmti/run-tests/test-920/Android.bp hostsidetests/jvmti/run-tests/test-920/app/Android.bp hostsidetests/jvmti/run-tests/test-922/Android.bp hostsidetests/jvmti/run-tests/test-922/app/Android.bp hostsidetests/jvmti/run-tests/test-923/Android.bp hostsidetests/jvmti/run-tests/test-923/app/Android.bp hostsidetests/jvmti/run-tests/test-924/Android.bp hostsidetests/jvmti/run-tests/test-924/app/Android.bp hostsidetests/jvmti/run-tests/test-926/Android.bp hostsidetests/jvmti/run-tests/test-926/app/Android.bp hostsidetests/jvmti/run-tests/test-927/Android.bp hostsidetests/jvmti/run-tests/test-927/app/Android.bp hostsidetests/jvmti/run-tests/test-928/Android.bp hostsidetests/jvmti/run-tests/test-928/app/Android.bp hostsidetests/jvmti/run-tests/test-930/Android.bp hostsidetests/jvmti/run-tests/test-930/app/Android.bp hostsidetests/jvmti/run-tests/test-931/Android.bp hostsidetests/jvmti/run-tests/test-931/app/Android.bp hostsidetests/jvmti/run-tests/test-932/Android.bp hostsidetests/jvmti/run-tests/test-932/app/Android.bp hostsidetests/jvmti/run-tests/test-940/Android.bp hostsidetests/jvmti/run-tests/test-940/app/Android.bp hostsidetests/jvmti/run-tests/test-942/Android.bp hostsidetests/jvmti/run-tests/test-942/app/Android.bp hostsidetests/jvmti/run-tests/test-944/Android.bp hostsidetests/jvmti/run-tests/test-944/app/Android.bp hostsidetests/jvmti/run-tests/test-945/Android.bp hostsidetests/jvmti/run-tests/test-945/app/Android.bp hostsidetests/jvmti/run-tests/test-947/Android.bp hostsidetests/jvmti/run-tests/test-947/app/Android.bp hostsidetests/jvmti/run-tests/test-951/Android.bp hostsidetests/jvmti/run-tests/test-951/app/Android.bp hostsidetests/jvmti/run-tests/test-982/Android.bp hostsidetests/jvmti/run-tests/test-982/app/Android.bp hostsidetests/jvmti/run-tests/test-983/Android.bp hostsidetests/jvmti/run-tests/test-983/app/Android.bp hostsidetests/jvmti/run-tests/test-984/Android.bp hostsidetests/jvmti/run-tests/test-984/app/Android.bp hostsidetests/jvmti/run-tests/test-985/Android.bp hostsidetests/jvmti/run-tests/test-985/app/Android.bp hostsidetests/jvmti/run-tests/test-986/Android.bp hostsidetests/jvmti/run-tests/test-986/app/Android.bp hostsidetests/jvmti/run-tests/test-988/Android.bp hostsidetests/jvmti/run-tests/test-988/app/Android.bp hostsidetests/jvmti/run-tests/test-989/Android.bp hostsidetests/jvmti/run-tests/test-989/app/Android.bp hostsidetests/jvmti/run-tests/test-990/Android.bp hostsidetests/jvmti/run-tests/test-990/app/Android.bp hostsidetests/jvmti/run-tests/test-991/Android.bp hostsidetests/jvmti/run-tests/test-991/app/Android.bp hostsidetests/jvmti/run-tests/test-992/Android.bp hostsidetests/jvmti/run-tests/test-992/app/Android.bp hostsidetests/jvmti/run-tests/test-993/Android.bp hostsidetests/jvmti/run-tests/test-993/app/Android.bp hostsidetests/jvmti/run-tests/test-994/Android.bp hostsidetests/jvmti/run-tests/test-994/app/Android.bp hostsidetests/jvmti/run-tests/test-995/Android.bp hostsidetests/jvmti/run-tests/test-995/app/Android.bp hostsidetests/jvmti/run-tests/test-996/Android.bp hostsidetests/jvmti/run-tests/test-996/app/Android.bp hostsidetests/jvmti/run-tests/test-997/Android.bp hostsidetests/jvmti/run-tests/test-997/app/Android.bp hostsidetests/jvmti/tagging/Android.bp hostsidetests/jvmti/tagging/app/Android.bp hostsidetests/media/Android.bp hostsidetests/media/app/MediaSessionTest/Android.bp hostsidetests/media/app/MediaSessionTestHelper/Android.bp hostsidetests/media/bitstreams/Android.bp hostsidetests/media/bitstreams/app/Android.bp hostsidetests/media/bitstreams/common/Android.bp hostsidetests/monkey/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.bp hostsidetests/multiuser/Android.bp hostsidetests/numberblocking/Android.bp hostsidetests/numberblocking/app/Android.bp hostsidetests/os/Android.bp hostsidetests/os/app/Android.bp hostsidetests/os/test-apps/EnvironmentTestApp/Android.bp hostsidetests/os/test-apps/HostLinkVerificationApp/Android.bp hostsidetests/os/test-apps/InattentiveSleepTestApp/Android.bp hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp hostsidetests/os/test-apps/ProcfsTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.bp hostsidetests/packagemanager/codepath/Android.bp hostsidetests/packagemanager/codepath/app/Android.bp hostsidetests/packagemanager/dynamicmime/Android.bp hostsidetests/packagemanager/dynamicmime/app/Android.bp hostsidetests/packagemanager/dynamicmime/common/Android.bp hostsidetests/packagemanager/dynamicmime/test/Android.bp hostsidetests/packagemanager/extractnativelibs/Android.bp hostsidetests/packagemanager/extractnativelibs/apps/Android.bp hostsidetests/rollback/Android.bp hostsidetests/sample/Android.bp hostsidetests/sample/app/Android.bp hostsidetests/sample/app2/Android.bp hostsidetests/scopedstorage/Android.bp hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp hostsidetests/seccomp/Android.bp hostsidetests/seccomp/app/Android.bp hostsidetests/seccomp/app/jni/Android.bp hostsidetests/security/Android.mk hostsidetests/securitybulletin/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-137878930/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-4658/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5131/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0814/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0840/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13241/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13253/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9472/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9491/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9347/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0069/Android.bp hostsidetests/securitybulletin/securityPatch/includes/Android.bp hostsidetests/securitybulletin/securityPatch/pac/Android.bp hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp hostsidetests/settings/Android.bp hostsidetests/settings/app/DeviceOwnerApp/Android.bp hostsidetests/shortcuts/deviceside/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher1/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher2/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher3/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher1/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher2/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher3/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nobackup/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_wrongkey/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/common/Android.bp hostsidetests/shortcuts/deviceside/multiuser/Android.bp hostsidetests/shortcuts/deviceside/upgrade/Android.bp hostsidetests/shortcuts/hostside/Android.bp hostsidetests/signedconfig/app/Android.bp hostsidetests/signedconfig/hostside/Android.bp hostsidetests/stagedinstall/Android.bp hostsidetests/sustainedperf/shadertoy_android/jni/Android.bp hostsidetests/systemui/Android.bp hostsidetests/systemui/app/Android.bp hostsidetests/systemui/audiorecorder_app_audiorecord/Android.bp hostsidetests/systemui/audiorecorder_app_mediarecorder/Android.bp hostsidetests/systemui/audiorecorder_base/Android.bp hostsidetests/tagging/Android.bp hostsidetests/tagging/common/Android.bp hostsidetests/tagging/manifest_disabled/Android.bp hostsidetests/tagging/manifest_enabled_sdk_29/Android.bp hostsidetests/tagging/manifest_enabled_sdk_30/Android.bp hostsidetests/tagging/sdk_29/Android.bp hostsidetests/tagging/sdk_30/Android.bp hostsidetests/telephony/Android.bp hostsidetests/telephony/devicetest/Android.bp hostsidetests/telephonyprovider/Android.bp hostsidetests/telephonyprovider/devicetest/Android.bp hostsidetests/testharness/Android.bp hostsidetests/testharness/app/Android.bp hostsidetests/theme/Android.mk hostsidetests/theme/app/Android.bp hostsidetests/trustedvoice/Android.bp hostsidetests/trustedvoice/app/Android.bp hostsidetests/tv/Android.bp hostsidetests/tv/app/Android.bp hostsidetests/tv/app2/Android.bp hostsidetests/tzdata/Android.bp hostsidetests/ui/Android.mk hostsidetests/ui/appA/Android.bp hostsidetests/ui/appB/Android.bp hostsidetests/ui/control/Android.bp hostsidetests/usage/Android.bp hostsidetests/usage/app/Android.bp hostsidetests/usb/Android.bp hostsidetests/usb/SerialTestApp/Android.bp hostsidetests/userspacereboot/Android.bp hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp hostsidetests/utils/Android.bp hostsidetests/webkit/Android.bp hostsidetests/webkit/app/Android.bp hostsidetests/wifibroadcasts/Android.bp hostsidetests/wifibroadcasts/app/Android.bp libs/deviceutillegacy/Android.bp libs/helpers/core/Android.bp libs/helpers/core/tests/Android.bp libs/helpers/interfaces/Android.bp libs/input/Android.bp libs/install/Android.bp libs/json/Android.bp libs/midi/Android.bp libs/rollback/Android.bp libs/shim/Android.bp libs/view/Android.bp libs/vogar-expect/Android.bp suite/audio_quality/executable/Android.bp suite/audio_quality/lib/Android.bp suite/audio_quality/test/Android.bp tests/AlarmManager/Android.bp tests/AlarmManager/app/Android.bp tests/BlobStore/Android.bp tests/DropBoxManager/Android.bp tests/JobScheduler/Android.bp tests/JobScheduler/JobTestApp/Android.bp tests/JobSchedulerSharedUid/Android.bp tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp tests/JobSchedulerSharedUid/jobperm/Android.bp tests/JobSchedulerSharedUid/shareduid/Android.bp tests/ProcessTest/Android.bp tests/ProcessTest/NoShareUidApp/Android.bp tests/ProcessTest/ShareUidApp/Android.bp tests/acceleration/Android.bp tests/accessibility/Android.bp tests/accessibilityservice/Android.bp tests/accessibilityservice/test-apps/WidgetProvider/Android.bp tests/accessibilityservice/testsdk29/Android.bp tests/admin/Android.bp tests/admin/app/Android.bp tests/app/ActivityManagerApi29Test/Android.bp tests/app/Android.bp tests/app/BadProviderStubs/Android.bp tests/app/CantSaveState1/Android.bp tests/app/CantSaveState2/Android.bp tests/app/NotificationDelegator/Android.bp tests/app/NotificationListener/Android.bp tests/app/NotificationProvider/Android.bp tests/app/StorageDelegator/Android.bp tests/app/app/Android.bp tests/appintegrity/Android.bp tests/apppredictionservice/Android.bp tests/aslr/Android.bp tests/attentionservice/Android.bp tests/autofillservice/Android.bp tests/backup/Android.bp tests/backup/app/Android.bp tests/bugreport/Android.bp tests/camera/Android.bp tests/camera/libctscamera2jni/Android.mk tests/camera/utils/Android.bp tests/contentcaptureservice/Android.bp tests/contentcaptureservice/OutsideOfPackageActivity/Android.bp tests/contentsuggestions/Android.bp tests/controls/Android.bp tests/core/runner-axt/Android.bp tests/filesystem/Android.bp tests/fragment/Android.bp tests/fragment/sdk26/Android.bp tests/framework/base/windowmanager/Android.bp tests/framework/base/windowmanager/alertwindowapp/Android.bp tests/framework/base/windowmanager/alertwindowappsdk25/Android.bp tests/framework/base/windowmanager/alertwindowservice/Android.bp tests/framework/base/windowmanager/app/Android.bp tests/framework/base/windowmanager/app27/Android.bp tests/framework/base/windowmanager/appAShareUid/Android.bp tests/framework/base/windowmanager/appBShareUid/Android.bp tests/framework/base/windowmanager/appDeprecatedSdk/Android.bp tests/framework/base/windowmanager/appDisplaySize/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp tests/framework/base/windowmanager/appProfileable/Android.bp tests/framework/base/windowmanager/appSecondUid/Android.bp tests/framework/base/windowmanager/appThirdUid/Android.bp tests/framework/base/windowmanager/app_base/Android.bp tests/framework/base/windowmanager/backgroundactivity/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppA/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppB/Android.bp tests/framework/base/windowmanager/backgroundactivity/common/Android.bp tests/framework/base/windowmanager/dndsourceapp/Android.bp tests/framework/base/windowmanager/dndtargetapp/Android.bp tests/framework/base/windowmanager/dndtargetappsdk23/Android.bp tests/framework/base/windowmanager/jetpack/Android.bp tests/framework/base/windowmanager/testsdk25/Android.bp tests/framework/base/windowmanager/testsdk28/Android.bp tests/framework/base/windowmanager/testsdk29/Android.bp tests/framework/base/windowmanager/translucentapp/Android.bp tests/framework/base/windowmanager/translucentappsdk26/Android.bp tests/framework/base/windowmanager/util/Android.bp tests/inputmethod/Android.bp tests/inputmethod/mockime/Android.bp tests/inputmethod/testapp/Android.bp tests/jdwp/Android.bp tests/jdwp/runner/device-side/Android.bp tests/jdwp/runner/host-side/Android.bp tests/leanbackjank/Android.bp tests/leanbackjank/app/Android.bp tests/libcore/jsr166/Android.bp tests/libcore/luni/Android.bp tests/libcore/ojluni/Android.bp tests/libcore/okhttp/Android.bp tests/libcore/runner/Android.bp tests/libcore/wycheproof-bc/Android.bp tests/libcore/wycheproof/Android.bp tests/location/common/Android.bp tests/location/location_coarse/Android.bp tests/location/location_fine/Android.bp tests/location/location_gnss/Android.bp tests/location/location_none/Android.bp tests/location/location_privileged/Android.bp tests/media/Android.bp tests/media/jni/Android.bp tests/mocking/Android.bp tests/mocking/debuggable/Android.bp tests/mocking/extended/Android.bp tests/mocking/inline/Android.bp tests/netlegacy22.permission/Android.bp tests/netsecpolicy/Android.bp tests/openglperf2/jni/Android.bp tests/pdf/Android.bp tests/providerui/Android.bp tests/quickaccesswallet/Android.bp tests/rollback/Android.bp tests/sample/Android.bp tests/security/Android.bp tests/sensor/Android.bp tests/signature/Android.bp tests/signature/api-check/Android.bp tests/signature/api-check/android-test-base-28-api/Android.bp tests/signature/api-check/android-test-base-current-api/Android.bp tests/signature/api-check/android-test-mock-current-api/Android.bp tests/signature/api-check/android-test-runner-current-api/Android.bp tests/signature/api-check/apache-http-legacy-27-api/Android.bp tests/signature/api-check/apache-http-legacy-current-api/Android.bp tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp tests/signature/api-check/current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-27-api/Android.bp tests/signature/api-check/hidden-api-blocklist-28-api/Android.bp tests/signature/api-check/hidden-api-blocklist-current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-debug-class/Android.bp tests/signature/api-check/hidden-api-blocklist-test-api/Android.bp tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp tests/signature/api-check/hidden-api-killswitch-sdklist/Android.bp tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp tests/signature/api-check/shared-libs-api/Android.mk tests/signature/api-check/system-annotation/Android.bp tests/signature/api-check/system-api/Android.mk tests/signature/dex-checker/Android.bp tests/signature/intent-check/Android.bp tests/signature/lib/android/Android.bp tests/signature/lib/common/Android.bp tests/signature/tests/Android.bp tests/simplecpu/jni/Android.bp tests/suspendapps/Android.bp tests/suspendapps/permission/Android.bp tests/suspendapps/test-apps/SuspendTestApp/Android.bp tests/suspendapps/test-apps/TestDeviceAdmin/Android.bp tests/suspendapps/tests/Android.bp tests/tests/accounts/Android.bp tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.bp tests/tests/accounts/common/Android.bp tests/tests/animation/Android.bp tests/tests/apache-http/Android.bp tests/tests/app.usage/Android.bp tests/tests/app.usage/TestApp1/Android.bp tests/tests/app/Android.bp tests/tests/appcomponentfactory/Android.bp tests/tests/appenumeration/Android.bp tests/tests/appenumeration/app/source/Android.bp tests/tests/appenumeration/app/target/Android.bp tests/tests/appenumeration/lib/Android.bp tests/tests/appop/Android.bp tests/tests/appop/AppInBackground/Android.bp tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp tests/tests/appop/AppThatUsesAppOps/Android.bp tests/tests/appop/AppToBlame1/Android.bp tests/tests/appop/AppToBlame2/Android.bp tests/tests/appop/AppToCollect/Android.bp tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp tests/tests/appop/AppWithDuplicateAttribution/Android.bp tests/tests/appop/AppWithLongAttributionTag/Android.bp tests/tests/appop/AppWithTooManyAttributions/Android.bp tests/tests/appop/aidl/AppOpsForegroundControlService/Android.bp tests/tests/appop/aidl/AppOpsUserService/Android.bp tests/tests/appop/appopsTestUtilLib/Android.bp tests/tests/appwidget/Android.bp tests/tests/appwidget/packages/launchermanifest/Android.bp tests/tests/appwidget/packages/widgetprovider/Android.bp tests/tests/assist/Android.bp tests/tests/assist/common/Android.bp tests/tests/assist/service/Android.bp tests/tests/assist/testapp/Android.bp tests/tests/background/Android.bp tests/tests/batterysaving/Android.bp tests/tests/batterysaving/apps/app_target_api_25/Android.bp tests/tests/batterysaving/apps/app_target_api_current/Android.bp tests/tests/batterysaving/common/Android.bp tests/tests/binder_ndk/Android.bp tests/tests/binder_ndk/libbinder_ndk_test/Android.bp tests/tests/bionic/Android.mk tests/tests/bionic_app/Android.bp tests/tests/bluetooth/Android.bp tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp tests/tests/calendarcommon/Android.bp tests/tests/calendarprovider/Android.bp tests/tests/car/Android.bp tests/tests/carrierapi/Android.bp tests/tests/classloaderfactory/Android.bp tests/tests/classloaderfactory/test-memcl/Android.bp tests/tests/classloaderfactory/test-pathcl/Android.bp tests/tests/colormode/Android.bp tests/tests/contactsprovider/Android.bp tests/tests/contactsprovider/gal/Android.bp tests/tests/contactsproviderwipe/Android.bp tests/tests/content/Android.bp tests/tests/content/BinderPermissionTestService/Android.bp tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.bp tests/tests/content/DirectBootUnawareTestApp/Android.bp tests/tests/content/HelloWorldApp/Android.bp tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp tests/tests/content/SyncAccountAccessStubs/Android.bp tests/tests/content/emptytestapp/Android.bp tests/tests/content/jni/Android.bp tests/tests/content/lib/accountaccess/Android.bp tests/tests/content/pm/SecureFrp/Android.bp tests/tests/cronet/Android.bp tests/tests/database/Android.bp tests/tests/database/apps/Android.bp tests/tests/deviceconfig/Android.bp tests/tests/display/Android.bp tests/tests/dpi/Android.bp tests/tests/dpi2/Android.bp tests/tests/dreams/Android.bp tests/tests/drm/Android.bp tests/tests/drm/jni/Android.bp tests/tests/drm/lib/Android.bp tests/tests/dynamic_linker/Android.bp tests/tests/effect/Android.bp tests/tests/externalservice/Android.bp tests/tests/externalservice/common/Android.bp tests/tests/externalservice/service/Android.bp tests/tests/gesture/Android.bp tests/tests/graphics/Android.bp tests/tests/graphics/jni/Android.bp tests/tests/gwp-asan/enabled/Android.bp tests/tests/hardware/Android.bp tests/tests/hardware/jni/Android.bp tests/tests/icu/Android.bp tests/tests/icu/icu4c_testapp/Android.bp tests/tests/identity/Android.bp tests/tests/instantapp/Android.bp tests/tests/jni/Android.bp tests/tests/jni/libjnicommon/Android.bp tests/tests/jni/libjnitest/Android.bp tests/tests/jvmti/attaching/Android.bp tests/tests/jvmti/attaching/jni/Android.bp tests/tests/keystore/Android.bp tests/tests/libcoreapievolution/Android.bp tests/tests/libcorefileio/Android.bp tests/tests/libcorelegacy22/Android.bp tests/tests/libnativehelper/Android.bp tests/tests/libnativehelper/jni/Android.bp tests/tests/libthermalndk/Android.bp tests/tests/libthermalndk/jni/Android.bp tests/tests/match_flags/Android.bp tests/tests/match_flags/app/a/Android.bp tests/tests/match_flags/app/b/Android.bp tests/tests/media/libaudiojni/Android.bp tests/tests/media/libimagereaderjni/Android.bp tests/tests/media/libndkaudio/Android.bp tests/tests/mediaparser/Android.bp tests/tests/mediastress/Android.bp tests/tests/mediastress/jni/Android.bp tests/tests/midi/Android.bp tests/tests/mimemap/Android.bp tests/tests/multiuser/Android.bp tests/tests/nativehardware/Android.bp tests/tests/nativehardware/jni/Android.bp tests/tests/nativemedia/aaudio/jni/Android.mk tests/tests/nativemedia/mediametrics/Android.bp tests/tests/nativemedia/sl/Android.mk tests/tests/nativemedia/xa/Android.mk tests/tests/nativemidi/jni/Android.mk tests/tests/ndef/Android.bp tests/tests/netpermission/internetpermission/Android.bp tests/tests/netpermission/updatestatspermission/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-false/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-true/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.bp tests/tests/networksecurityconfig/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.bp tests/tests/neuralnetworks/Android.mk tests/tests/neuralnetworks/tflite_delegate/Android.mk tests/tests/nfc/Android.bp tests/tests/notificationlegacy/notificationlegacy20/Android.bp tests/tests/notificationlegacy/notificationlegacy27/Android.bp tests/tests/notificationlegacy/notificationlegacy28/Android.bp tests/tests/notificationlegacy/notificationlegacy29/Android.bp tests/tests/opengl/Android.bp tests/tests/opengl/libopengltest/Android.bp tests/tests/openglperf/Android.bp tests/tests/openglperf/jni/Android.bp tests/tests/os/Android.bp tests/tests/os/Android.mk tests/tests/os/AutoRevokeDummyApp/Android.bp tests/tests/os/AutoRevokePreRApp/Android.bp tests/tests/os/jni/Android.bp tests/tests/packageinstaller/adminpackageinstaller/Android.bp tests/tests/packageinstaller/atomicinstall/Android.bp tests/tests/packageinstaller/emptytestapp/Android.bp tests/tests/packageinstaller/install/Android.bp tests/tests/packageinstaller/install_appop_default/Android.bp tests/tests/packageinstaller/install_appop_denied/Android.bp tests/tests/packageinstaller/nopermission/Android.bp tests/tests/packageinstaller/nopermission25/Android.bp tests/tests/packageinstaller/tapjacking/Android.bp tests/tests/packageinstaller/uninstall/Android.bp tests/tests/packagewatchdog/Android.bp tests/tests/permission/Android.bp tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp tests/tests/permission/AppThatRequestContactsPermission15/Android.bp tests/tests/permission/AppThatRequestContactsPermission16/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission22/Android.bp tests/tests/permission/AppThatRequestLocationPermission28/Android.bp tests/tests/permission/AppThatRequestLocationPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp tests/tests/permission/AppThatRequestOneTimePermission/Android.bp tests/tests/permission/AppThatRequestPermissionAandB/Android.bp tests/tests/permission/AppThatRequestPermissionAandC/Android.bp tests/tests/permission/AppThatRequestStoragePermission28/Android.bp tests/tests/permission/AppThatRequestStoragePermission29/Android.bp tests/tests/permission/AppThatRunsRationaleTests/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp tests/tests/permission/jni/Android.bp tests/tests/permission/permissionTestUtilLib/Android.bp tests/tests/permission/sdk28/Android.bp tests/tests/permission/telephony/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp tests/tests/permission2/Android.bp tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp tests/tests/permission3/Android.bp tests/tests/permission3/PermissionEscalationAppNonRuntime/Android.bp tests/tests/permission3/PermissionEscalationAppRuntime/Android.bp tests/tests/permission3/PermissionPolicyApp25/Android.bp tests/tests/permission3/UsePermissionApp22/Android.bp tests/tests/permission3/UsePermissionApp22CalendarOnly/Android.bp tests/tests/permission3/UsePermissionApp23/Android.bp tests/tests/permission3/UsePermissionApp25/Android.bp tests/tests/permission3/UsePermissionApp26/Android.bp tests/tests/permission3/UsePermissionApp28/Android.bp tests/tests/permission3/UsePermissionApp29/Android.bp tests/tests/permission3/UsePermissionAppLatest/Android.bp tests/tests/permission3/UsePermissionAppLatestWithBackground/Android.bp tests/tests/permission3/UsePermissionAppWithOverlay/Android.bp tests/tests/permission4/Android.bp tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp tests/tests/preference/Android.bp tests/tests/print/Android.bp tests/tests/print/ExternalPrintService/Android.bp tests/tests/print/printTestUtilLib/Android.bp tests/tests/proto/Android.bp tests/tests/provider/Android.bp tests/tests/provider/app/GalleryTestApp/Android.bp tests/tests/provider/preconditions/Android.bp tests/tests/renderscript/libcoremathtestcpp/Android.bp tests/tests/resolverservice/Android.bp tests/tests/resourcesloader/Android.bp tests/tests/resourcesloader/resources/Android.bp tests/tests/role/Android.bp tests/tests/role/CtsRoleTestApp/Android.bp tests/tests/role/CtsRoleTestApp28/Android.bp tests/tests/rsblas/libbnnmdata/Android.bp tests/tests/rscpp/librscpptest/Android.mk tests/tests/sax/Android.bp tests/tests/secure_element/access_control/AccessControlApp1/Android.bp tests/tests/secure_element/access_control/AccessControlApp2/Android.bp tests/tests/secure_element/access_control/AccessControlApp3/Android.bp tests/tests/secure_element/omapi/Android.bp tests/tests/security/Android.bp tests/tests/security/jni/Android.bp tests/tests/security/native/encryption/Android.bp tests/tests/security/native/verified_boot/Android.bp tests/tests/security/testeffect/Android.bp tests/tests/selinux/common/jni/Android.bp tests/tests/selinux/selinuxEphemeral/Android.bp tests/tests/selinux/selinuxTargetSdk25/Android.bp tests/tests/selinux/selinuxTargetSdk27/Android.bp tests/tests/selinux/selinuxTargetSdk28/Android.bp tests/tests/selinux/selinuxTargetSdk29/Android.bp tests/tests/selinux/selinuxTargetSdkCurrent/Android.bp tests/tests/settings/Android.bp tests/tests/sharesheet/Android.bp tests/tests/sharesheet/packages/Android.bp tests/tests/shortcutmanager/Android.bp tests/tests/simphonebookprovider/Android.bp tests/tests/simphonebookprovider/nosim/Android.bp tests/tests/simpleperf/Android.mk tests/tests/simpleperf/CtsSimpleperfDebuggableApp/Android.bp tests/tests/simpleperf/CtsSimpleperfProfileableApp/Android.bp tests/tests/slice/Android.bp tests/tests/soundtrigger/Android.bp tests/tests/speech/Android.bp tests/tests/syncmanager/Android.bp tests/tests/syncmanager/apps/Android.bp tests/tests/syncmanager/common/Android.bp tests/tests/systemintents/Android.bp tests/tests/systemui/Android.bp tests/tests/telecom/Android.bp tests/tests/telecom/Api29InCallServiceTestApp/Android.bp tests/tests/telecom/CallRedirectionServiceTestApp/Android.bp tests/tests/telecom/CallScreeningServiceTestApp/Android.bp tests/tests/telecom/CarModeTestApp/Android.bp tests/tests/telecom/CarModeTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyDialerTestApp/Android.bp tests/tests/telecom/ThirdPtyDialerTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyInCallServiceTestApp/Android.bp tests/tests/telecom2/Android.bp tests/tests/telecom3/Android.bp tests/tests/telephony/TestFinancialSmsApp/Android.bp tests/tests/telephony/TestSmsApp/Android.bp tests/tests/telephony/TestSmsApp22/Android.bp tests/tests/telephony/TestSmsRetrieverApp/Android.bp tests/tests/telephony/current/Android.bp tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp tests/tests/telephony/current/permissions/Android.bp tests/tests/telephony/current/preconditions/Android.bp tests/tests/telephony/current/preconditions/app/Android.bp tests/tests/telephony/current/src/android/telephony/cts/util/Android.bp tests/tests/telephony/sdk28/Android.bp tests/tests/telephony2/Android.bp tests/tests/telephony3/Android.bp tests/tests/telephony4/Android.bp tests/tests/telephonyprovider/Android.bp tests/tests/text/Android.bp tests/tests/text/jni/Android.bp tests/tests/textclassifier/Android.bp tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp tests/tests/theme/Android.bp tests/tests/toast/Android.bp tests/tests/toastlegacy/Android.bp tests/tests/tools/processors/view_inspector/Android.bp tests/tests/transition/Android.bp tests/tests/tv/Android.bp tests/tests/uiautomation/Android.bp tests/tests/uidisolation/Android.bp tests/tests/uirendering/Android.bp tests/tests/uirendering27/Android.bp tests/tests/usb/Android.bp tests/tests/util/Android.bp tests/tests/vcn/Android.bp tests/tests/view/jni/Android.bp tests/tests/view/sdk28/Android.bp tests/tests/view/surfacevalidator/Android.mk tests/tests/voiceinteraction/Android.bp tests/tests/voiceinteraction/common/Android.bp tests/tests/voiceinteraction/service/Android.bp tests/tests/voiceinteraction/testapp/Android.bp tests/tests/voicesettings/Android.bp tests/tests/voicesettings/service/Android.bp tests/tests/webkit/Android.bp tests/tests/widget/Android.bp tests/tests/widget/app/Android.bp tests/tests/widget29/Android.bp tests/tests/wifi/Android.bp tests/tests/wifi/CtsWifiLocationTestApp/Android.bp tests/tvprovider/Android.bp tests/video/Android.bp tests/vr/Android.bp tests/vr/jni/Android.bp tools/cfassembler/Android.bp tools/cts-api-coverage/Android.bp tools/cts-device-info/jni/Android.bp tools/cts-dynamic-config/Android.mk tools/cts-holo-generation/Android.bp tools/cts-media-preparer-app/Android.bp tools/cts-preconditions/Android.bp tools/cts-tradefed/Android.bp tools/cts-tradefed/tests/Android.bp tools/device-setup/TestDeviceSetup/Android.bp tools/manifest-generator/Android.bp tools/manifest-generator/tests/Android.bp tools/release-parser/Android.bp tools/release-parser/tests/Android.bp tools/vm-tests-tf/Android.bp tools/vm-tests-tf/Android.mk tools/vm-tests-tf/targetprep/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/testserver/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY to: apps/CtsVerifier/Android.bp apps/CtsVerifier/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-MIT SPDX-license-identifier-NCSA legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CC-BY legacy_unencumbered to: tests/tests/media/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: hostsidetests/gputools/Android.bp hostsidetests/gputools/layers/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-NCSA to: hostsidetests/appsecurity/certs/Android.bp hostsidetests/appsecurity/certs/keysets/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/testdata/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestAppPrebuilt/Android.bp hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/Android.bp libs/runner/Android.bp tests/BlobStore/certs/Android.bp tests/signature/api/Android.bp tests/signature/api/Android.mk tests/tests/telephony4/certs/Android.bp Added SPDX-license-identifier-Apache-2.0 legacy_unencumbered to: tests/tests/media/libmediandkjni/Android.bp Added SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/dhrystone/Android.mk Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ic8cb360bb718dfc853494a63deb3faee25cc04f7 Merged-in: Id84d4796cbbf3c4760088f8693c7f0617172e85e Merged-in: I1f04fce4093152fe75df9038c9d8cfabd5ce8049 Merged-in: Ic644accf6525269191f42c8acb62d7674778c76a Merged-in: I358f30ded3b8ffdb93dd64df5fd3a1826ddcf940 Merged-in: Ife18970b70627be2cdd765dac9035625f039d416 Merged-in: Ibb634168b6d2e4a43e9832e5777fd08611592bc9 --- Vcn/tests/cts/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 5666ee78a5..ecb1236b9b 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test { name: "CtsVcnTestCases", defaults: ["cts_defaults"], From f2686bad5f4a1b5b9a5c07497ce01599e136ccfc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 19 Jan 2021 17:19:39 -0800 Subject: [PATCH 0068/1057] Expose Basic VCN API surface This change exposes the Basics of the VCN API surface, including: - VCN Configurations - VCN Gateway Configuration superclass (Builder in subclasses) - VcnManger with configuration management APIs Bug: 168833866 Test: atest FrameworksVcnTests Test: atest android.net.vcn Change-Id: Ia1b3597d903dd84267f66546a90437f9ac45b2de --- .../src/android/net/vcn/VcnConfig.java | 19 ++---- .../net/vcn/VcnGatewayConnectionConfig.java | 62 +++++++------------ .../src/android/net/vcn/VcnManager.java | 24 +++---- 3 files changed, 38 insertions(+), 67 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index 5eb4ba6a2f..52cc2182b0 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -20,6 +20,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.NetworkRequest; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -41,7 +42,6 @@ import java.util.Set; * brought up on demand based on active {@link NetworkRequest}(s). * * @see VcnManager for more information on the Virtual Carrier Network feature - * @hide */ public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); @@ -56,7 +56,8 @@ public final class VcnConfig implements Parcelable { @NonNull String packageName, @NonNull Set gatewayConnectionConfigs) { mPackageName = packageName; - mGatewayConnectionConfigs = Collections.unmodifiableSet(gatewayConnectionConfigs); + mGatewayConnectionConfigs = + Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs)); validate(); } @@ -96,11 +97,7 @@ public final class VcnConfig implements Parcelable { return mPackageName; } - /** - * Retrieves the set of configured tunnels. - * - * @hide - */ + /** Retrieves the set of configured GatewayConnection(s). */ @NonNull public Set getGatewayConnectionConfigs() { return Collections.unmodifiableSet(mGatewayConnectionConfigs); @@ -168,11 +165,7 @@ public final class VcnConfig implements Parcelable { } }; - /** - * This class is used to incrementally build {@link VcnConfig} objects. - * - * @hide - */ + /** This class is used to incrementally build {@link VcnConfig} objects. */ public static final class Builder { @NonNull private final String mPackageName; @@ -190,7 +183,6 @@ public final class VcnConfig implements Parcelable { * * @param gatewayConnectionConfig the configuration for an individual gateway connection * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull public Builder addGatewayConnectionConfig( @@ -205,7 +197,6 @@ public final class VcnConfig implements Parcelable { * Builds and validates the VcnConfig. * * @return an immutable VcnConfig instance - * @hide */ @NonNull public VcnConfig build() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index cead2f1caa..40aa518c7b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -21,6 +21,8 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.net.Network; import android.net.NetworkCapabilities; import android.os.PersistableBundle; import android.util.ArraySet; @@ -55,28 +57,23 @@ import java.util.concurrent.TimeUnit; * subscription group under which this configuration is registered (see {@link * VcnManager#setVcnConfig}). * - *

    Services that can be provided by a VCN network, or required for underlying networks are - * limited to services provided by cellular networks: + *

    As an abstraction of a cellular network, services that can be provided by a VCN network, or + * required for underlying networks are limited to services provided by cellular networks: * *

      - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_MMS} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_SUPL} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_DUN} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_FOTA} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_IMS} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_CBS} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_IA} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_RCS} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_XCAP} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_EIMS} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET} - *
    • {@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_MMS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_SUPL} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_DUN} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_FOTA} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_IMS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_CBS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_IA} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_RCS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_XCAP} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_EIMS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_MCX} *
    - * - *

    The meteredness and roaming of the VCN {@link Network} will be determined by that of the - * underlying Network(s). - * - * @hide */ public final class VcnGatewayConnectionConfig { // TODO: Use MIN_MTU_V6 once it is public, @hide @@ -249,8 +246,7 @@ public final class VcnGatewayConnectionConfig { * ascending numerical order. * * @see Builder#addExposedCapability(int) - * @see Builder#clearExposedCapability(int) - * @hide + * @see Builder#removeExposedCapability(int) */ @NonNull public int[] getExposedCapabilities() { @@ -278,8 +274,7 @@ public final class VcnGatewayConnectionConfig { *

    The returned integer-value capabilities will be sorted in ascending numerical order. * * @see Builder#addRequiredUnderlyingCapability(int) - * @see Builder#clearRequiredUnderlyingCapability(int) - * @hide + * @see Builder#removeRequiredUnderlyingCapability(int) */ @NonNull public int[] getRequiredUnderlyingCapabilities() { @@ -305,7 +300,6 @@ public final class VcnGatewayConnectionConfig { * Retrieves the configured retry intervals. * * @see Builder#setRetryInterval(long[]) - * @hide */ @NonNull public long[] getRetryInterval() { @@ -317,7 +311,7 @@ public final class VcnGatewayConnectionConfig { * *

    Left to prevent the need to make major changes while changes are actively in flight. * - * @deprecated use getRequiredUnderlyingCapabilities() instead + * @deprecated use getRetryInterval() instead * @hide */ @Deprecated @@ -329,8 +323,7 @@ public final class VcnGatewayConnectionConfig { /** * Retrieves the maximum MTU allowed for this Gateway Connection. * - * @see Builder.setMaxMtu(int) - * @hide + * @see Builder#setMaxMtu(int) */ @IntRange(from = MIN_MTU_V6) public int getMaxMtu() { @@ -388,8 +381,6 @@ public final class VcnGatewayConnectionConfig { /** * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. - * - * @hide */ public static final class Builder { @NonNull private final Set mExposedCapabilities = new ArraySet(); @@ -409,7 +400,6 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection - * @hide */ @NonNull public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) { @@ -427,10 +417,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection - * @hide */ @NonNull - public Builder clearExposedCapability(@VcnSupportedCapability int exposedCapability) { + @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap + public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -445,7 +435,6 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks - * @hide */ @NonNull public Builder addRequiredUnderlyingCapability( @@ -468,10 +457,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks - * @hide */ @NonNull - public Builder clearRequiredUnderlyingCapability( + @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap + public Builder removeRequiredUnderlyingCapability( @VcnSupportedCapability int underlyingCapability) { checkValidCapability(underlyingCapability); @@ -501,7 +490,6 @@ public final class VcnGatewayConnectionConfig { * 15m]} * @return this {@link Builder} instance, for chaining * @see VcnManager for additional discussion on fail-safe mode - * @hide */ @NonNull public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { @@ -523,7 +511,6 @@ public final class VcnGatewayConnectionConfig { * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than * the IPv6 minimum MTU of 1280. Defaults to 1500. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { @@ -538,7 +525,6 @@ public final class VcnGatewayConnectionConfig { * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance - * @hide */ @NonNull public VcnGatewayConnectionConfig build() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 1a38338c26..467043665d 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -39,12 +39,12 @@ import java.util.concurrent.Executor; /** * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. * - *

    A VCN creates a virtualization layer to allow MVNOs to aggregate heterogeneous physical + *

    A VCN creates a virtualization layer to allow carriers to aggregate heterogeneous physical * networks, unifying them as a single carrier network. This enables infrastructure flexibility on - * the part of MVNOs without impacting user connectivity, abstracting the physical network + * the part of carriers without impacting user connectivity, abstracting the physical network * technologies as an implementation detail of their public network. * - *

    Each VCN virtualizes an Carrier's network by building tunnels to a carrier's core network over + *

    Each VCN virtualizes a carrier's network by building tunnels to a carrier's core network over * carrier-managed physical links and supports a IP mobility layer to ensure seamless transitions * between the underlying networks. Each VCN is configured based on a Subscription Group (see {@link * android.telephony.SubscriptionManager}) and aggregates all networks that are brought up based on @@ -62,8 +62,6 @@ import java.util.concurrent.Executor; * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default. * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will * automatically exit Safe Mode if all active tunnels connect successfully. - * - * @hide */ @SystemService(Context.VCN_MANAGEMENT_SERVICE) public class VcnManager { @@ -101,7 +99,6 @@ public class VcnManager { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } - // TODO: Make setVcnConfig(), clearVcnConfig() Public API /** * Sets the VCN configuration for a given subscription group. * @@ -113,11 +110,10 @@ public class VcnManager { * * @param subscriptionGroup the subscription group that the configuration should be applied to * @param config the configuration parameters for the VCN - * @throws SecurityException if the caller does not have carrier privileges, or is not running - * as the primary user - * @throws IOException if the configuration failed to be persisted. A caller encountering this - * exception should attempt to retry (possibly after a delay). - * @hide + * @throws SecurityException if the caller does not have carrier privileges for the provided + * subscriptionGroup, or is not running as the primary user + * @throws IOException if the configuration failed to be saved and persisted to disk. This may + * occur due to temporary disk errors, or more permanent conditions such as a full disk. */ @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) @@ -134,7 +130,6 @@ public class VcnManager { } } - // TODO: Make setVcnConfig(), clearVcnConfig() Public API /** * Clears the VCN configuration for a given subscription group. * @@ -145,9 +140,8 @@ public class VcnManager { * @param subscriptionGroup the subscription group that the configuration should be applied to * @throws SecurityException if the caller does not have carrier privileges, or is not running * as the primary user - * @throws IOException if the configuration failed to be cleared. A caller encountering this - * exception should attempt to retry (possibly after a delay). - * @hide + * @throws IOException if the configuration failed to be cleared from disk. This may occur due + * to temporary disk errors, or more permanent conditions such as a full disk. */ @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) throws IOException { From b5d7a6d87a39abf5ba41ca52e24f57de92c9cb40 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Sat, 6 Feb 2021 16:48:45 -0800 Subject: [PATCH 0069/1057] Define VcnStatusCallback register/unregister. This CL defines VcnStatusCallbacks, which are callbacks used to register for status updates to a specific subscription group. These Callbacks may be registered with VcnManager at any time, but will only be invoked for the specifies subscription group and only if the registering app has carrier privileges for that subscription. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: Iefd284ae2d09676d195e2a12bf660be3596da59b --- .../net/vcn/IVcnManagementService.aidl | 4 + .../android/net/vcn/IVcnStatusCallback.aidl | 22 +++ .../src/android/net/vcn/VcnManager.java | 120 ++++++++++++++++- .../android/server/VcnManagementService.java | 127 ++++++++++++++++-- .../src/com/android/server/vcn/Vcn.java | 16 +-- .../java/android/net/vcn/VcnManagerTest.java | 63 +++++++++ .../server/VcnManagementServiceTest.java | 65 ++++++++- .../java/com/android/server/vcn/VcnTest.java | 14 +- 8 files changed, 395 insertions(+), 36 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 4f293eeb3c..6a3cb42ed7 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -18,6 +18,7 @@ package android.net.vcn; import android.net.LinkProperties; import android.net.NetworkCapabilities; +import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnUnderlyingNetworkPolicy; @@ -33,4 +34,7 @@ interface IVcnManagementService { void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp); + + void registerVcnStatusCallback(in ParcelUuid subscriptionGroup, in IVcnStatusCallback callback, in String opPkgName); + void unregisterVcnStatusCallback(in IVcnStatusCallback callback); } diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl new file mode 100644 index 0000000000..a7386718d5 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl @@ -0,0 +1,22 @@ +/* + * Copyright 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 android.net.vcn; + +/** @hide */ +interface IVcnStatusCallback { + void onEnteredSafeMode(); +} \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 1a38338c26..4d110d0fbf 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemService; import android.content.Context; import android.net.LinkProperties; import android.net.NetworkCapabilities; +import android.os.Binder; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -267,6 +268,100 @@ public class VcnManager { } } + // TODO: make VcnStatusCallback @SystemApi + /** + * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs. + * + *

    VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a + * subscription group. + * + * @hide + */ + public abstract static class VcnStatusCallback { + private VcnStatusCallbackBinder mCbBinder; + + /** + * Invoked when the VCN for this Callback's subscription group enters safe mode. + * + *

    A VCN will be put into safe mode if any of the gateway connections were unable to + * establish a connection within a system-determined timeout (while underlying networks were + * available). + * + *

    A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration + * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. + */ + public abstract void onEnteredSafeMode(); + } + + /** + * Registers the given callback to receive status updates for the specified subscription. + * + *

    Callbacks can be registered for a subscription before {@link VcnConfig}s are set for it. + * + *

    A {@link VcnStatusCallback} may only be registered for one subscription at a time. {@link + * VcnStatusCallback}s may be reused once unregistered. + * + *

    A {@link VcnStatusCallback} will only be invoked if the registering package has carrier + * privileges for the specified subscription at the time of invocation. + * + * @param subscriptionGroup The subscription group to match for callbacks + * @param executor The {@link Executor} to be used for invoking callbacks + * @param callback The VcnStatusCallback to be registered + * @throws IllegalStateException if callback is currently registered with VcnManager + * @hide + */ + public void registerVcnStatusCallback( + @NonNull ParcelUuid subscriptionGroup, + @NonNull Executor executor, + @NonNull VcnStatusCallback callback) { + requireNonNull(subscriptionGroup, "subscriptionGroup must not be null"); + requireNonNull(executor, "executor must not be null"); + requireNonNull(callback, "callback must not be null"); + + synchronized (callback) { + if (callback.mCbBinder != null) { + throw new IllegalStateException("callback is already registered with VcnManager"); + } + callback.mCbBinder = new VcnStatusCallbackBinder(executor, callback); + + try { + mService.registerVcnStatusCallback( + subscriptionGroup, callback.mCbBinder, mContext.getOpPackageName()); + } catch (RemoteException e) { + callback.mCbBinder = null; + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Unregisters the given callback. + * + *

    Once unregistered, the callback will stop receiving status updates for the subscription it + * was registered with. + * + * @param callback The callback to be unregistered + * @hide + */ + public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) { + requireNonNull(callback, "callback must not be null"); + + synchronized (callback) { + if (callback.mCbBinder == null) { + // no Binder attached to this callback, so it's not currently registered + return; + } + + try { + mService.unregisterVcnStatusCallback(callback.mCbBinder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } finally { + callback.mCbBinder = null; + } + } + } + /** * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System * Server. @@ -286,7 +381,30 @@ public class VcnManager { @Override public void onPolicyChanged() { - mExecutor.execute(() -> mListener.onPolicyChanged()); + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> mListener.onPolicyChanged())); + } + } + + /** + * Binder wrapper for VcnStatusCallbacks to receive signals from VcnManagementService. + * + * @hide + */ + private class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub { + @NonNull private final Executor mExecutor; + @NonNull private final VcnStatusCallback mCallback; + + private VcnStatusCallbackBinder( + @NonNull Executor executor, @NonNull VcnStatusCallback callback) { + mExecutor = executor; + mCallback = callback; + } + + @Override + public void onEnteredSafeMode() { + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); } } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 27210daac2..ed7f7837a7 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -29,6 +29,7 @@ import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnManagementService; +import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnUnderlyingNetworkPolicy; @@ -124,6 +125,7 @@ import java.util.concurrent.TimeUnit; * * @hide */ +// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); @@ -169,6 +171,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { private final Map mRegisteredPolicyListeners = new ArrayMap<>(); + @GuardedBy("mLock") + @NonNull + private final Map mRegisteredStatusCallbacks = new ArrayMap<>(); + @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { mContext = requireNonNull(context, "Missing context"); @@ -293,8 +299,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafemodeCallback safemodeCallback) { - return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safemodeCallback); + @NonNull VcnSafeModeCallback safeModeCallback) { + return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safeModeCallback); } /** Gets the subId indicated by the given {@link WifiInfo}. */ @@ -440,12 +446,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. - final VcnSafemodeCallbackImpl safemodeCallback = - new VcnSafemodeCallbackImpl(subscriptionGroup); + final VcnSafeModeCallbackImpl safeModeCallback = + new VcnSafeModeCallbackImpl(subscriptionGroup); final Vcn newInstance = mDeps.newVcn( - mVcnContext, subscriptionGroup, config, mLastSnapshot, safemodeCallback); + mVcnContext, subscriptionGroup, config, mLastSnapshot, safeModeCallback); mVcns.put(subscriptionGroup, newInstance); // Now that a new VCN has started, notify all registered listeners to refresh their @@ -551,6 +557,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + /** Get current VcnStatusCallbacks for testing purposes. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Map getAllStatusCallbacks() { + synchronized (mLock) { + return Collections.unmodifiableMap(mRegisteredStatusCallbacks); + } + } + /** Binder death recipient used to remove a registered policy listener. */ private class PolicyListenerBinderDeath implements Binder.DeathRecipient { @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener; @@ -672,22 +686,109 @@ public class VcnManagementService extends IVcnManagementService.Stub { return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); } - /** Callback for signalling when a Vcn has entered Safemode. */ - public interface VcnSafemodeCallback { - /** Called by a Vcn to signal that it has entered Safemode. */ - void onEnteredSafemode(); + /** Binder death recipient used to remove registered VcnStatusCallbacks. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + class VcnStatusCallbackInfo implements Binder.DeathRecipient { + @NonNull final ParcelUuid mSubGroup; + @NonNull final IVcnStatusCallback mCallback; + @NonNull final String mPkgName; + final int mUid; + + private VcnStatusCallbackInfo( + @NonNull ParcelUuid subGroup, + @NonNull IVcnStatusCallback callback, + @NonNull String pkgName, + int uid) { + mSubGroup = subGroup; + mCallback = callback; + mPkgName = pkgName; + mUid = uid; + } + + @Override + public void binderDied() { + Log.e(TAG, "app died without unregistering VcnStatusCallback"); + unregisterVcnStatusCallback(mCallback); + } } - /** VcnSafemodeCallback is used by Vcns to notify VcnManagementService on entering Safemode. */ - private class VcnSafemodeCallbackImpl implements VcnSafemodeCallback { + /** Registers the provided callback for receiving VCN status updates. */ + @Override + public void registerVcnStatusCallback( + @NonNull ParcelUuid subGroup, + @NonNull IVcnStatusCallback callback, + @NonNull String opPkgName) { + final int callingUid = mDeps.getBinderCallingUid(); + final long identity = Binder.clearCallingIdentity(); + try { + requireNonNull(subGroup, "subGroup must not be null"); + requireNonNull(callback, "callback must not be null"); + requireNonNull(opPkgName, "opPkgName must not be null"); + + mContext.getSystemService(AppOpsManager.class).checkPackage(callingUid, opPkgName); + + final IBinder cbBinder = callback.asBinder(); + final VcnStatusCallbackInfo cbInfo = + new VcnStatusCallbackInfo( + subGroup, callback, opPkgName, mDeps.getBinderCallingUid()); + + try { + cbBinder.linkToDeath(cbInfo, 0 /* flags */); + } catch (RemoteException e) { + // Remote binder already died - don't add to mRegisteredStatusCallbacks and exit + return; + } + + synchronized (mLock) { + if (mRegisteredStatusCallbacks.containsKey(cbBinder)) { + throw new IllegalStateException( + "Attempting to register a callback that is already in use"); + } + + mRegisteredStatusCallbacks.put(cbBinder, cbInfo); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + /** Unregisters the provided callback from receiving future VCN status updates. */ + @Override + public void unregisterVcnStatusCallback(@NonNull IVcnStatusCallback callback) { + final long identity = Binder.clearCallingIdentity(); + try { + requireNonNull(callback, "callback must not be null"); + + final IBinder cbBinder = callback.asBinder(); + synchronized (mLock) { + VcnStatusCallbackInfo cbInfo = mRegisteredStatusCallbacks.remove(cbBinder); + + if (cbInfo != null) { + cbBinder.unlinkToDeath(cbInfo, 0 /* flags */); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService + /** Callback for signalling when a Vcn has entered safe mode. */ + public interface VcnSafeModeCallback { + /** Called by a Vcn to signal that it has entered safe mode. */ + void onEnteredSafeMode(); + } + + /** VcnSafeModeCallback is used by Vcns to notify VcnManagementService on entering safe mode. */ + private class VcnSafeModeCallbackImpl implements VcnSafeModeCallback { @NonNull private final ParcelUuid mSubGroup; - private VcnSafemodeCallbackImpl(@NonNull final ParcelUuid subGroup) { + private VcnSafeModeCallbackImpl(@NonNull final ParcelUuid subGroup) { mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup"); } @Override - public void onEnteredSafemode() { + public void onEnteredSafeMode() { synchronized (mLock) { // Ignore if this subscription group doesn't exist anymore if (!mVcns.containsKey(mSubGroup)) { diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 3726407211..d4374a453f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -30,7 +30,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.server.VcnManagementService.VcnSafemodeCallback; +import com.android.server.VcnManagementService.VcnSafeModeCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.Collections; @@ -97,7 +97,7 @@ public class Vcn extends Handler { @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Dependencies mDeps; @NonNull private final VcnNetworkRequestListener mRequestListener; - @NonNull private final VcnSafemodeCallback mVcnSafemodeCallback; + @NonNull private final VcnSafeModeCallback mVcnSafeModeCallback; @NonNull private final Map mVcnGatewayConnections = @@ -125,13 +125,13 @@ public class Vcn extends Handler { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafemodeCallback vcnSafemodeCallback) { + @NonNull VcnSafeModeCallback vcnSafeModeCallback) { this( vcnContext, subscriptionGroup, config, snapshot, - vcnSafemodeCallback, + vcnSafeModeCallback, new Dependencies()); } @@ -141,13 +141,13 @@ public class Vcn extends Handler { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafemodeCallback vcnSafemodeCallback, + @NonNull VcnSafeModeCallback vcnSafeModeCallback, @NonNull Dependencies deps) { super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); - mVcnSafemodeCallback = - Objects.requireNonNull(vcnSafemodeCallback, "Missing vcnSafemodeCallback"); + mVcnSafeModeCallback = + Objects.requireNonNull(vcnSafeModeCallback, "Missing vcnSafeModeCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mRequestListener = new VcnNetworkRequestListener(); @@ -246,7 +246,7 @@ public class Vcn extends Handler { private void handleEnterSafemode() { handleTeardown(); - mVcnSafemodeCallback.onEnteredSafemode(); + mVcnSafeModeCallback.onEnteredSafeMode(); } private void handleNetworkRequested( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 7dada9d1b6..1a90fc319b 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -26,24 +26,30 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.content.Context; import android.net.LinkProperties; import android.net.NetworkCapabilities; +import android.net.vcn.VcnManager.VcnStatusCallback; import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; +import android.os.ParcelUuid; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.util.UUID; import java.util.concurrent.Executor; public class VcnManagerTest { + private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final Executor INLINE_EXECUTOR = Runnable::run; private IVcnManagementService mMockVcnManagementService; private VcnUnderlyingNetworkPolicyListener mMockPolicyListener; + private VcnStatusCallback mMockStatusCallback; private Context mContext; private VcnManager mVcnManager; @@ -52,6 +58,7 @@ public class VcnManagerTest { public void setUp() { mMockVcnManagementService = mock(IVcnManagementService.class); mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class); + mMockStatusCallback = mock(VcnStatusCallback.class); mContext = getContext(); mVcnManager = new VcnManager(mContext, mMockVcnManagementService); @@ -132,4 +139,60 @@ public class VcnManagerTest { public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception { mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null); } + + @Test + public void testRegisterVcnStatusCallback() throws Exception { + mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(IVcnStatusCallback.class); + verify(mMockVcnManagementService) + .registerVcnStatusCallback(eq(SUB_GROUP), captor.capture(), any()); + + IVcnStatusCallback callbackWrapper = captor.getValue(); + callbackWrapper.onEnteredSafeMode(); + verify(mMockStatusCallback).onEnteredSafeMode(); + } + + @Test(expected = IllegalStateException.class) + public void testRegisterVcnStatusCallbackAlreadyRegistered() throws Exception { + mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback); + mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback); + } + + @Test(expected = NullPointerException.class) + public void testRegisterVcnStatusCallbackNullSubscriptionGroup() throws Exception { + mVcnManager.registerVcnStatusCallback(null, INLINE_EXECUTOR, mMockStatusCallback); + } + + @Test(expected = NullPointerException.class) + public void testRegisterVcnStatusCallbackNullExecutor() throws Exception { + mVcnManager.registerVcnStatusCallback(SUB_GROUP, null, mMockStatusCallback); + } + + @Test(expected = NullPointerException.class) + public void testRegisterVcnStatusCallbackNullCallback() throws Exception { + mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, null); + } + + @Test + public void testUnregisterVcnStatusCallback() throws Exception { + mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback); + + mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback); + + verify(mMockVcnManagementService).unregisterVcnStatusCallback(any()); + } + + @Test + public void testUnregisterUnknownVcnStatusCallback() throws Exception { + mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback); + + verifyNoMoreInteractions(mMockVcnManagementService); + } + + @Test(expected = NullPointerException.class) + public void testUnregisterNullVcnStatusCallback() throws Exception { + mVcnManager.unregisterVcnStatusCallback(null); + } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index c290bff188..f258ab4465 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -26,6 +26,7 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService; 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; @@ -52,6 +53,7 @@ import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.NetworkCapabilities.Transport; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; @@ -70,7 +72,8 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.VcnManagementService.VcnSafemodeCallback; +import com.android.server.VcnManagementService.VcnSafeModeCallback; +import com.android.server.VcnManagementService.VcnStatusCallbackInfo; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; @@ -148,13 +151,14 @@ public class VcnManagementServiceTest { private final TelephonySubscriptionTracker mSubscriptionTracker = mock(TelephonySubscriptionTracker.class); - private final ArgumentCaptor mSafemodeCallbackCaptor = - ArgumentCaptor.forClass(VcnSafemodeCallback.class); + private final ArgumentCaptor mSafeModeCallbackCaptor = + ArgumentCaptor.forClass(VcnSafeModeCallback.class); private final VcnManagementService mVcnMgmtSvc; private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener = mock(IVcnUnderlyingNetworkPolicyListener.class); + private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class); private final IBinder mMockIBinder = mock(IBinder.class); public VcnManagementServiceTest() throws Exception { @@ -206,6 +210,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); + doReturn(mMockIBinder).when(mMockStatusCallback).asBinder(); // Make sure the profiles are loaded. mTestLooper.dispatchAll(); @@ -708,7 +713,7 @@ public class VcnManagementServiceTest { } @Test - public void testVcnSafemodeCallbackOnEnteredSafemode() throws Exception { + public void testVcnSafeModeCallbackOnEnteredSafeMode() throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); verify(mMockDeps) @@ -717,14 +722,60 @@ public class VcnManagementServiceTest { eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), - mSafemodeCallbackCaptor.capture()); + mSafeModeCallbackCaptor.capture()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - VcnSafemodeCallback safemodeCallback = mSafemodeCallbackCaptor.getValue(); - safemodeCallback.onEnteredSafemode(); + VcnSafeModeCallback safeModeCallback = mSafeModeCallbackCaptor.getValue(); + safeModeCallback.onEnteredSafeMode(); assertFalse(mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1).isActive()); verify(mMockPolicyListener).onPolicyChanged(); } + + @Test + public void testRegisterVcnStatusCallback() throws Exception { + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + Map callbacks = mVcnMgmtSvc.getAllStatusCallbacks(); + VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder); + + assertNotNull(cbInfo); + assertEquals(TEST_UUID_1, cbInfo.mSubGroup); + assertEquals(mMockStatusCallback, cbInfo.mCallback); + assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName); + assertEquals(TEST_UID, cbInfo.mUid); + verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt()); + } + + @Test(expected = IllegalStateException.class) + public void testRegisterVcnStatusCallbackDuplicate() { + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + } + + @Test + public void testUnregisterVcnStatusCallback() { + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + Map callbacks = mVcnMgmtSvc.getAllStatusCallbacks(); + VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder); + + mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback); + assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty()); + verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt()); + } + + @Test(expected = SecurityException.class) + public void testRegisterVcnStatusCallbackInvalidPackage() { + doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + } + + @Test + public void testUnregisterVcnStatusCallbackNeverRegistered() { + mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback); + + assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 66cbf84619..1f510a2ac7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -34,7 +34,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; -import com.android.server.VcnManagementService.VcnSafemodeCallback; +import com.android.server.VcnManagementService.VcnSafeModeCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; @@ -56,7 +56,7 @@ public class VcnTest { private VcnContext mVcnContext; private TelephonySubscriptionSnapshot mSubscriptionSnapshot; private VcnNetworkProvider mVcnNetworkProvider; - private VcnSafemodeCallback mVcnSafemodeCallback; + private VcnSafeModeCallback mVcnSafeModeCallback; private Vcn.Dependencies mDeps; private ArgumentCaptor mGatewayStatusCallbackCaptor; @@ -72,7 +72,7 @@ public class VcnTest { mVcnContext = mock(VcnContext.class); mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); mVcnNetworkProvider = mock(VcnNetworkProvider.class); - mVcnSafemodeCallback = mock(VcnSafemodeCallback.class); + mVcnSafeModeCallback = mock(VcnSafeModeCallback.class); mDeps = mock(Vcn.Dependencies.class); mTestLooper = new TestLooper(); @@ -104,7 +104,7 @@ public class VcnTest { TEST_SUB_GROUP, mConfig, mSubscriptionSnapshot, - mVcnSafemodeCallback, + mVcnSafeModeCallback, mDeps); } @@ -148,7 +148,7 @@ public class VcnTest { } @Test - public void testGatewayEnteringSafemodeNotifiesVcn() { + public void testGatewayEnteringSafeModeNotifiesVcn() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { startVcnGatewayWithCapabilities(requestListener, capability); @@ -168,7 +168,7 @@ public class VcnTest { any(), mGatewayStatusCallbackCaptor.capture()); - // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down + // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down // all Gateways final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); statusCallback.onEnteredSafemode(); @@ -178,6 +178,6 @@ public class VcnTest { verify(gatewayConnection).teardownAsynchronously(); } verify(mVcnNetworkProvider).unregisterListener(requestListener); - verify(mVcnSafemodeCallback).onEnteredSafemode(); + verify(mVcnSafeModeCallback).onEnteredSafeMode(); } } From 11e9b2b7814e278357fa54a7e0ab8720a321e35f Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Sun, 14 Feb 2021 16:45:30 -0800 Subject: [PATCH 0070/1057] Change all 'safemode' references to use 'safe mode'. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I5daced209e4e6d8d1b87385b3f64660322908fa0 --- .../src/com/android/server/vcn/Vcn.java | 22 +++---- .../server/vcn/VcnGatewayConnection.java | 62 +++++++++---------- ...cnGatewayConnectionConnectedStateTest.java | 22 +++---- ...nGatewayConnectionConnectingStateTest.java | 4 +- ...atewayConnectionDisconnectedStateTest.java | 4 +- ...tewayConnectionDisconnectingStateTest.java | 4 +- ...atewayConnectionRetryTimeoutStateTest.java | 4 +- .../vcn/VcnGatewayConnectionTestBase.java | 18 +++--- .../java/com/android/server/vcn/VcnTest.java | 2 +- 9 files changed, 71 insertions(+), 71 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index d4374a453f..02a597e9aa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -86,12 +86,12 @@ public class Vcn extends Handler { private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; /** - * Causes this VCN to immediately enter Safemode. + * Causes this VCN to immediately enter safe mode. * - *

    Upon entering Safemode, the VCN will unregister its RequestListener, tear down all of its - * VcnGatewayConnections, and notify VcnManagementService that it is in Safemode. + *

    Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its + * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode. */ - private static final int MSG_CMD_ENTER_SAFEMODE = MSG_CMD_BASE + 1; + private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1; @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @@ -216,8 +216,8 @@ public class Vcn extends Handler { case MSG_CMD_TEARDOWN: handleTeardown(); break; - case MSG_CMD_ENTER_SAFEMODE: - handleEnterSafemode(); + case MSG_CMD_ENTER_SAFE_MODE: + handleEnterSafeMode(); break; default: Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); @@ -243,7 +243,7 @@ public class Vcn extends Handler { mIsActive.set(false); } - private void handleEnterSafemode() { + private void handleEnterSafeMode() { handleTeardown(); mVcnSafeModeCallback.onEnteredSafeMode(); @@ -335,14 +335,14 @@ public class Vcn extends Handler { /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ @VisibleForTesting(visibility = Visibility.PACKAGE) public interface VcnGatewayStatusCallback { - /** Called by a VcnGatewayConnection to indicate that it has entered Safemode. */ - void onEnteredSafemode(); + /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */ + void onEnteredSafeMode(); } private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { @Override - public void onEnteredSafemode() { - sendMessage(obtainMessage(MSG_CMD_ENTER_SAFEMODE)); + public void onEnteredSafeMode() { + sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 0ed26dbe83..91573a8adb 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -418,13 +418,13 @@ public class VcnGatewayConnection extends StateMachine { private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9; /** - * Sent when this VcnGatewayConnection has entered Safemode. + * Sent when this VcnGatewayConnection has entered safe mode. * - *

    A VcnGatewayConnection enters Safemode when it takes over {@link + *

    A VcnGatewayConnection enters safe mode when it takes over {@link * #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}. * *

    When a VcnGatewayConnection enters safe mode, it will fire {@link - * VcnGatewayStatusCallback#onEnteredSafemode()} to notify its Vcn. The Vcn will then shut down + * VcnGatewayStatusCallback#onEnteredSafeMode()} to notify its Vcn. The Vcn will then shut down * its VcnGatewayConnectin(s). * *

    Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not @@ -432,7 +432,7 @@ public class VcnGatewayConnection extends StateMachine { * * @param arg1 The "all" token; this signal is always honored. */ - private static final int EVENT_SAFEMODE_TIMEOUT_EXCEEDED = 10; + private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10; @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull @@ -551,7 +551,7 @@ public class VcnGatewayConnection extends StateMachine { @Nullable private WakeupMessage mTeardownTimeoutAlarm; @Nullable private WakeupMessage mDisconnectRequestAlarm; @Nullable private WakeupMessage mRetryTimeoutAlarm; - @Nullable private WakeupMessage mSafemodeTimeoutAlarm; + @Nullable private WakeupMessage mSafeModeTimeoutAlarm; public VcnGatewayConnection( @NonNull VcnContext vcnContext, @@ -638,7 +638,7 @@ public class VcnGatewayConnection extends StateMachine { cancelTeardownTimeoutAlarm(); cancelDisconnectRequestAlarm(); cancelRetryTimeoutAlarm(); - cancelSafemodeAlarm(); + cancelSafeModeAlarm(); mUnderlyingNetworkTracker.teardown(); } @@ -928,27 +928,27 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setSafemodeAlarm() { + void setSafeModeAlarm() { // Only schedule a NEW alarm if none is already set. - if (mSafemodeTimeoutAlarm != null) { + if (mSafeModeTimeoutAlarm != null) { return; } - final Message delayedMessage = obtainMessage(EVENT_SAFEMODE_TIMEOUT_EXCEEDED, TOKEN_ALL); - mSafemodeTimeoutAlarm = + final Message delayedMessage = obtainMessage(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED, TOKEN_ALL); + mSafeModeTimeoutAlarm = createScheduledAlarm( SAFEMODE_TIMEOUT_ALARM, delayedMessage, TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); } - private void cancelSafemodeAlarm() { - if (mSafemodeTimeoutAlarm != null) { - mSafemodeTimeoutAlarm.cancel(); - mSafemodeTimeoutAlarm = null; + private void cancelSafeModeAlarm() { + if (mSafeModeTimeoutAlarm != null) { + mSafeModeTimeoutAlarm.cancel(); + mSafeModeTimeoutAlarm = null; } - removeEqualMessages(EVENT_SAFEMODE_TIMEOUT_EXCEEDED); + removeEqualMessages(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED); } private void sessionLost(int token, @Nullable Exception exception) { @@ -1125,7 +1125,7 @@ public class VcnGatewayConnection extends StateMachine { Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); } - cancelSafemodeAlarm(); + cancelSafeModeAlarm(); } @Override @@ -1153,7 +1153,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void exitState() { // Safe to blindly set up, as it is cancelled and cleared on entering this state - setSafemodeAlarm(); + setSafeModeAlarm(); } } @@ -1245,9 +1245,9 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mDisconnectedState); } break; - case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafemode(); - mSafemodeTimeoutAlarm = null; + case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafeMode(); + mSafeModeTimeoutAlarm = null; break; default: logUnhandledMessage(msg); @@ -1331,9 +1331,9 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; - case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafemode(); - mSafemodeTimeoutAlarm = null; + case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafeMode(); + mSafeModeTimeoutAlarm = null; break; default: logUnhandledMessage(msg); @@ -1399,7 +1399,7 @@ public class VcnGatewayConnection extends StateMachine { // Validated connection, clear failed attempt counter mFailedAttempts = 0; - cancelSafemodeAlarm(); + cancelSafeModeAlarm(); } protected void applyTransform( @@ -1517,9 +1517,9 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; - case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafemode(); - mSafemodeTimeoutAlarm = null; + case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafeMode(); + mSafeModeTimeoutAlarm = null; break; default: logUnhandledMessage(msg); @@ -1574,7 +1574,7 @@ public class VcnGatewayConnection extends StateMachine { protected void exitState() { // Attempt to set the safe mode alarm - this requires the Vcn Network being validated // while in ConnectedState (which cancels the previous alarm) - setSafemodeAlarm(); + setSafeModeAlarm(); } } @@ -1622,9 +1622,9 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); break; - case EVENT_SAFEMODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafemode(); - mSafemodeTimeoutAlarm = null; + case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: + mGatewayStatusCallback.onEnteredSafeMode(); + mSafeModeTimeoutAlarm = null; break; default: logUnhandledMessage(msg); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index a6eae96100..5eeebf027d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -75,8 +75,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } @Test - public void testEnterStateDoesNotCancelSafemodeAlarm() { - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + public void testEnterStateDoesNotCancelSafeModeAlarm() { + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -130,7 +130,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testChildOpenedRegistersNetwork() throws Exception { // Verify scheduled but not canceled when entering ConnectedState - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); final VcnChildSessionConfiguration mMockChildSessionConfig = mock(VcnChildSessionConfiguration.class); @@ -174,17 +174,17 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertTrue(nc.hasCapability(cap)); } - // Now that Vcn Network is up, notify it as validated and verify the Safemode alarm is + // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is // canceled mGatewayConnection.mNetworkAgent.onValidationStatus( NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */); - verify(mSafemodeTimeoutAlarm).cancel(); + verify(mSafeModeTimeoutAlarm).cancel(); } @Test public void testChildSessionClosedTriggersDisconnect() throws Exception { // Verify scheduled but not canceled when entering ConnectedState - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); getChildSessionCallback().onClosed(); mTestLooper.dispatchAll(); @@ -192,14 +192,14 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); - // Since network never validated, verify mSafemodeTimeoutAlarm not canceled - verifyNoMoreInteractions(mSafemodeTimeoutAlarm); + // Since network never validated, verify mSafeModeTimeoutAlarm not canceled + verifyNoMoreInteractions(mSafeModeTimeoutAlarm); } @Test public void testIkeSessionClosedTriggersDisconnect() throws Exception { // Verify scheduled but not canceled when entering ConnectedState - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); getIkeSessionCallback().onClosed(); mTestLooper.dispatchAll(); @@ -207,7 +207,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verify(mIkeSession).close(); - // Since network never validated, verify mSafemodeTimeoutAlarm not canceled - verifyNoMoreInteractions(mSafemodeTimeoutAlarm); + // Since network never validated, verify mSafeModeTimeoutAlarm not canceled + verifyNoMoreInteractions(mSafeModeTimeoutAlarm); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 07282c9200..17ae19e086 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -108,7 +108,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio } @Test - public void testSafemodeTimeoutNotifiesCallback() { - verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); + public void testSafeModeTimeoutNotifiesCallback() { + verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 49ce54d4f6..9ea641f52e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -79,7 +79,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); } @Test @@ -100,6 +100,6 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); - verifySafemodeTimeoutAlarmAndGetCallback(true /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 22eab2a1aa..7385204993 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -82,7 +82,7 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec } @Test - public void testSafemodeTimeoutNotifiesCallback() { - verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); + public void testSafeModeTimeoutNotifiesCallback() { + verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 6c26075866..5b0850b03f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -93,7 +93,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect } @Test - public void testSafemodeTimeoutNotifiesCallback() { - verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); + public void testSafeModeTimeoutNotifiesCallback() { + verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index ac9ec0663d..a660735470 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -110,7 +110,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final WakeupMessage mTeardownTimeoutAlarm; @NonNull protected final WakeupMessage mDisconnectRequestAlarm; @NonNull protected final WakeupMessage mRetryTimeoutAlarm; - @NonNull protected final WakeupMessage mSafemodeTimeoutAlarm; + @NonNull protected final WakeupMessage mSafeModeTimeoutAlarm; @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; @@ -131,7 +131,7 @@ public class VcnGatewayConnectionTestBase { mTeardownTimeoutAlarm = mock(WakeupMessage.class); mDisconnectRequestAlarm = mock(WakeupMessage.class); mRetryTimeoutAlarm = mock(WakeupMessage.class); - mSafemodeTimeoutAlarm = mock(WakeupMessage.class); + mSafeModeTimeoutAlarm = mock(WakeupMessage.class); mIpSecSvc = mock(IpSecService.class); setupIpSecManager(mContext, mIpSecSvc); @@ -154,7 +154,7 @@ public class VcnGatewayConnectionTestBase { setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM); setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM); setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM); - setUpWakeupMessage(mSafemodeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM); + setUpWakeupMessage(mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM); doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime(); } @@ -259,23 +259,23 @@ public class VcnGatewayConnectionTestBase { expectCanceled); } - protected Runnable verifySafemodeTimeoutAlarmAndGetCallback(boolean expectCanceled) { + protected Runnable verifySafeModeTimeoutAlarmAndGetCallback(boolean expectCanceled) { return verifyWakeupMessageSetUpAndGetCallback( VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, - mSafemodeTimeoutAlarm, + mSafeModeTimeoutAlarm, TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS), expectCanceled); } - protected void verifySafemodeTimeoutNotifiesCallback(@NonNull State expectedState) { - // Safemode timer starts when VcnGatewayConnection exits DisconnectedState (the initial + protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) { + // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial // state) final Runnable delayedEvent = - verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); delayedEvent.run(); mTestLooper.dispatchAll(); - verify(mGatewayStatusCallback).onEnteredSafemode(); + verify(mGatewayStatusCallback).onEnteredSafeMode(); assertEquals(expectedState, mGatewayConnection.getCurrentState()); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 1f510a2ac7..5b37c80bd3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -171,7 +171,7 @@ public class VcnTest { // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down // all Gateways final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); - statusCallback.onEnteredSafemode(); + statusCallback.onEnteredSafeMode(); mTestLooper.dispatchAll(); for (final VcnGatewayConnection gatewayConnection : gatewayConnections) { From 118bc92875ac569601bd963b096336d0f74fe88d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Sun, 7 Feb 2021 12:40:53 -0800 Subject: [PATCH 0071/1057] Notify status callbacks when a VCN enters Safemode. This CL updates VcnManagementService to notify VcnStatusCallbacks when the VCN for their specified subscription group enters Safemode. In order to be notified, the registering app must also have permissions for the specified permission. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I3242ad0ee1dc406aef56253f884c2544a994869e --- .../android/server/VcnManagementService.java | 32 +++++++ .../server/VcnManagementServiceTest.java | 89 +++++++++++++++++-- .../java/com/android/server/vcn/VcnTest.java | 1 + 3 files changed, 116 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index ed7f7837a7..ed4e1d951b 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -22,6 +22,7 @@ import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubsc import static java.util.Objects.requireNonNull; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; @@ -55,6 +56,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.LocationPermissionChecker; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; @@ -149,6 +151,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; @NonNull private final VcnContext mVcnContext; + /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */ + @Nullable private LocationPermissionChecker mLocationPermissionChecker; + @GuardedBy("mLock") @NonNull private final Map mConfigs = new ArrayMap<>(); @@ -308,6 +313,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + + /** Creates a new LocationPermissionChecker for the provided Context. */ + public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) { + return new LocationPermissionChecker(context); + } } /** Notifies the VcnManagementService that external dependencies can be set up. */ @@ -315,6 +325,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(ConnectivityManager.class) .registerNetworkProvider(mNetworkProvider); mTelephonySubscriptionTracker.register(); + mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext()); } private void enforcePrimaryUser() { @@ -796,6 +807,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } notifyAllPolicyListenersLocked(); + + // Notify all registered StatusCallbacks for this subGroup + for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { + if (!mSubGroup.equals(cbInfo.mSubGroup)) { + continue; + } + if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup( + mSubGroup, cbInfo.mPkgName)) { + continue; + } + + if (!mLocationPermissionChecker.checkLocationPermission( + cbInfo.mPkgName, + "VcnStatusCallback" /* featureId */, + cbInfo.mUid, + null /* message */)) { + continue; + } + + Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); + } } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index f258ab4465..124ec3056f 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -43,9 +43,11 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; @@ -72,6 +74,7 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.LocationPermissionChecker; import com.android.server.VcnManagementService.VcnSafeModeCallback; import com.android.server.VcnManagementService.VcnStatusCallbackInfo; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -150,6 +153,8 @@ public class VcnManagementServiceTest { mock(PersistableBundleUtils.LockingReadWriteHelper.class); private final TelephonySubscriptionTracker mSubscriptionTracker = mock(TelephonySubscriptionTracker.class); + private final LocationPermissionChecker mLocationPermissionChecker = + mock(LocationPermissionChecker.class); private final ArgumentCaptor mSafeModeCallbackCaptor = ArgumentCaptor.forClass(VcnSafeModeCallback.class); @@ -175,6 +180,7 @@ public class VcnManagementServiceTest { doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName(); + doReturn(mMockContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper(); doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid(); doReturn(mVcnContext) @@ -192,6 +198,9 @@ public class VcnManagementServiceTest { doReturn(mConfigReadWriteHelper) .when(mMockDeps) .newPersistableBundleLockingReadWriteHelper(any()); + doReturn(mLocationPermissionChecker) + .when(mMockDeps) + .newLocationPermissionChecker(eq(mMockContext)); // Setup VCN instance generation doAnswer((invocation) -> { @@ -712,14 +721,13 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } - @Test - public void testVcnSafeModeCallbackOnEnteredSafeMode() throws Exception { - TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + private void verifyVcnSafeModeCallback( + @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) + throws Exception { verify(mMockDeps) .newVcn( eq(mVcnContext), - eq(TEST_UUID_1), + eq(subGroup), eq(TEST_VCN_CONFIG), eq(snapshot), mSafeModeCallbackCaptor.capture()); @@ -729,10 +737,79 @@ public class VcnManagementServiceTest { VcnSafeModeCallback safeModeCallback = mSafeModeCallbackCaptor.getValue(); safeModeCallback.onEnteredSafeMode(); - assertFalse(mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1).isActive()); verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testVcnSafeModeCallbackOnEnteredSafeMode() throws Exception { + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + + verifyVcnSafeModeCallback(TEST_UUID_1, snapshot); + } + + private void triggerVcnStatusCallbackOnEnteredSafeMode( + @NonNull ParcelUuid subGroup, + @NonNull String pkgName, + int uid, + boolean hasPermissionsforSubGroup, + boolean hasLocationPermission) + throws Exception { + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + + doReturn(hasPermissionsforSubGroup) + .when(snapshot) + .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName)); + + doReturn(hasLocationPermission) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(pkgName), any(), eq(uid), any()); + + mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); + + // Trigger systemReady() to set up LocationPermissionChecker + mVcnMgmtSvc.systemReady(); + + verifyVcnSafeModeCallback(subGroup, snapshot); + } + + @Test + public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception { + triggerVcnStatusCallbackOnEnteredSafeMode( + TEST_UUID_1, + TEST_PACKAGE_NAME, + TEST_UID, + true /* hasPermissionsforSubGroup */, + true /* hasLocationPermission */); + + verify(mMockStatusCallback, times(1)).onEnteredSafeMode(); + } + + @Test + public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception { + triggerVcnStatusCallbackOnEnteredSafeMode( + TEST_UUID_1, + TEST_PACKAGE_NAME, + TEST_UID, + false /* hasPermissionsforSubGroup */, + true /* hasLocationPermission */); + + verify(mMockStatusCallback, never()).onEnteredSafeMode(); + } + + @Test + public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception { + triggerVcnStatusCallbackOnEnteredSafeMode( + TEST_UUID_1, + TEST_PACKAGE_NAME, + TEST_UID, + true /* hasPermissionsforSubGroup */, + false /* hasLocationPermission */); + + verify(mMockStatusCallback, never()).onEnteredSafeMode(); + } + @Test public void testRegisterVcnStatusCallback() throws Exception { mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 5b37c80bd3..8e142c095a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -174,6 +174,7 @@ public class VcnTest { statusCallback.onEnteredSafeMode(); mTestLooper.dispatchAll(); + assertFalse(mVcn.isActive()); for (final VcnGatewayConnection gatewayConnection : gatewayConnections) { verify(gatewayConnection).teardownAsynchronously(); } From 561094bfb1f713d78e0026cf3eab8a82d93b0f6d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 13 Jan 2021 18:03:41 -0800 Subject: [PATCH 0072/1057] Create VcnControlPlaneConfig and VcnControlPlaneIkeConfig VcnControlPlaneConfig contains control plane configuration for a VCN gateway connection. VcnControlPlaneIkeConfig is a subclass that contains IKE configuration. The followup CL will store VcnControlPlaneConfig in VcnGatewayConnectionConfig. Bug: 163604823 Test: FrameworksVcnTests(new tests added) Change-Id: If7a85ae44e77fc4477b56ffa50c6e99ee96132d0 --- .../net/vcn/VcnControlPlaneConfig.java | 107 +++++++++++++ .../net/vcn/VcnControlPlaneIkeConfig.java | 142 ++++++++++++++++++ .../net/vcn/VcnControlPlaneIkeConfigTest.java | 118 +++++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java new file mode 100644 index 0000000000..a49999ed01 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java @@ -0,0 +1,107 @@ +/* + * 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 android.net.vcn; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.PersistableBundle; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * This class represents a control plane configuration for a Virtual Carrier Network connection. + * + *

    Each {@link VcnGatewayConnectionConfig} must have a {@link VcnControlPlaneConfig}, containing + * all connection, authentication and authorization parameters required to establish a Gateway + * Connection with a remote endpoint. + * + *

    A {@link VcnControlPlaneConfig} object can be shared by multiple {@link + * VcnGatewayConnectionConfig}(s) if they will used for connecting with the same remote endpoint. + * + * @see VcnManager + * @see VcnGatewayConnectionConfig + * + * @hide + */ +public abstract class VcnControlPlaneConfig { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({CONFIG_TYPE_IKE}) + public @interface ConfigType {} + + /** @hide */ + public static final int CONFIG_TYPE_IKE = 1; + + private static final String CONFIG_TYPE_KEY = "mConfigType"; + @ConfigType private final int mConfigType; + + /** + * Package private constructor. + * + * @hide + */ + VcnControlPlaneConfig(int configType) { + mConfigType = configType; + } + + /** + * Constructs a VcnControlPlaneConfig object by deserializing a PersistableBundle. + * + * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneConfig} object + * @hide + */ + public static VcnControlPlaneConfig fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + int configType = in.getInt(CONFIG_TYPE_KEY); + switch (configType) { + case CONFIG_TYPE_IKE: + return new VcnControlPlaneIkeConfig(in); + default: + throw new IllegalStateException("Unrecognized configType: " + configType); + } + } + + /** + * Converts this VcnControlPlaneConfig to a PersistableBundle. + * + * @hide + */ + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + result.putInt(CONFIG_TYPE_KEY, mConfigType); + return result; + } + + /** @hide */ + @Override + public int hashCode() { + return Objects.hash(mConfigType); + } + + /** @hide */ + @Override + public boolean equals(Object o) { + if (!(o instanceof VcnControlPlaneConfig)) { + return false; + } + + return mConfigType == ((VcnControlPlaneConfig) o).mConfigType; + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java new file mode 100644 index 0000000000..f85a502f78 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java @@ -0,0 +1,142 @@ +/* + * 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 android.net.vcn; + +import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.PersistableBundle; +import android.util.ArraySet; + +import java.util.Objects; + +/** + * This class is an IKEv2 control plane configuration for a Virtual Carrier Network connection. + * + *

    This class is an extension of the {@link VcnControlPlaneConfig}, containing IKEv2-specific + * configuration, authentication and authorization parameters. + * + * @see VcnControlPlaneConfig + * + * @hide + */ +public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { + private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName(); + + // STOPSHIP: b/163604823 Make mIkeParams and mChildParams @NonNull when it is supported to + // construct mIkeParams and mChildParams from PersistableBundles. + + private static final String IKE_PARAMS_KEY = "mIkeParams"; + @Nullable private final IkeSessionParams mIkeParams; + + private static final String CHILD_PARAMS_KEY = "mChildParams"; + @Nullable private final TunnelModeChildSessionParams mChildParams; + + private static final ArraySet BUNDLE_KEY_SET = new ArraySet<>(); + + { + BUNDLE_KEY_SET.add(IKE_PARAMS_KEY); + BUNDLE_KEY_SET.add(CHILD_PARAMS_KEY); + } + + /** + * Constructs a VcnControlPlaneIkeConfig object. + * + * @param ikeParams the IKE Session negotiation parameters + * @param childParams the tunnel mode Child Session negotiation parameters + */ + public VcnControlPlaneIkeConfig( + @NonNull IkeSessionParams ikeParams, + @NonNull TunnelModeChildSessionParams childParams) { + super(CONFIG_TYPE_IKE); + mIkeParams = ikeParams; + mChildParams = childParams; + validate(); + } + + /** + * Constructs a VcnControlPlaneIkeConfig object by deserializing a PersistableBundle. + * + * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneIkeConfig} object + * @hide + */ + public VcnControlPlaneIkeConfig(@NonNull PersistableBundle in) { + super(CONFIG_TYPE_IKE); + final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY); + final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY); + + // STOPSHIP: b/163604823 Support constructing mIkeParams and mChildParams from + // PersistableBundles. + + mIkeParams = null; + mChildParams = null; + } + + private void validate() { + Objects.requireNonNull(mIkeParams, "mIkeParams was null"); + Objects.requireNonNull(mChildParams, "mChildParams was null"); + } + + /** + * Converts this VcnControlPlaneConfig to a PersistableBundle. + * + * @hide + */ + @Override + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = super.toPersistableBundle(); + + // STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to + // PersistableBundles. + return result; + } + + /** Retrieves the IKE Session configuration. */ + @NonNull + public IkeSessionParams getIkeSessionParams() { + return mIkeParams; + } + + /** Retrieves the tunnel mode Child Session configuration. */ + @NonNull + public TunnelModeChildSessionParams getChildSessionParams() { + return mChildParams; + } + + /** @hide */ + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), mIkeParams, mChildParams); + } + + /** @hide */ + @Override + public boolean equals(Object o) { + if (!(o instanceof VcnControlPlaneIkeConfig)) { + return false; + } + + VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o; + return super.equals(o) + && Objects.equals(mIkeParams, other.mIkeParams) + && Objects.equals(mChildParams, other.mChildParams); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java new file mode 100644 index 0000000000..36f5e41462 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java @@ -0,0 +1,118 @@ +/* + * 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.vcn; + +import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.SaProposal; +import android.net.ipsec.ike.TunnelModeChildSessionParams; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnControlPlaneIkeConfigTest { + private static final IkeSessionParams IKE_PARAMS; + private static final TunnelModeChildSessionParams CHILD_PARAMS; + + static { + IkeSaProposal ikeProposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addDhGroup(DH_GROUP_2048_BIT_MODP) + .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) + .build(); + + Context mockContext = mock(Context.class); + ConnectivityManager mockConnectManager = mock(ConnectivityManager.class); + doReturn(mockConnectManager) + .when(mockContext) + .getSystemService(Context.CONNECTIVITY_SERVICE); + doReturn(mock(Network.class)).when(mockConnectManager).getActiveNetwork(); + + final String serverHostname = "192.0.2.100"; + final String testLocalId = "test.client.com"; + final String testRemoteId = "test.server.com"; + final byte[] psk = "psk".getBytes(); + + IKE_PARAMS = + new IkeSessionParams.Builder(mockContext) + .setServerHostname(serverHostname) + .addSaProposal(ikeProposal) + .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) + .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) + .setAuthPsk(psk) + .build(); + + ChildSaProposal childProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .build(); + CHILD_PARAMS = + new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); + } + + // Package private for use in VcnGatewayConnectionConfigTest + static VcnControlPlaneIkeConfig buildTestConfig() { + return new VcnControlPlaneIkeConfig(IKE_PARAMS, CHILD_PARAMS); + } + + @Test + public void testGetters() { + final VcnControlPlaneIkeConfig config = buildTestConfig(); + assertEquals(IKE_PARAMS, config.getIkeSessionParams()); + assertEquals(CHILD_PARAMS, config.getChildSessionParams()); + } + + @Test + public void testConstructConfigWithoutIkeParams() { + try { + new VcnControlPlaneIkeConfig(null, CHILD_PARAMS); + fail("Expect to fail because ikeParams was null"); + } catch (NullPointerException expected) { + } + } + + @Test + public void testBuilderConfigWithoutChildParams() { + try { + new VcnControlPlaneIkeConfig(IKE_PARAMS, null); + fail("Expect to fail because childParams was null"); + } catch (NullPointerException expected) { + } + } +} From f3e43b9e9fa3fe98479f6586e6a5eb56ecf1b815 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 18 Jan 2021 22:13:10 -0800 Subject: [PATCH 0073/1057] Store VcnControlPlaneConfig in VcnGatewayConnectionConfig This CL requires callers to set a VcnControlPlaneConfig for building VcnGatewayConnectionConfig Bug: 163604823 Test: FrameworksVcnTests (new tests added) Change-Id: If45cb2aa866d627f3bb9762309fe8b07bf729ba8 --- .../net/vcn/VcnControlPlaneConfig.java | 7 +++ .../net/vcn/VcnControlPlaneIkeConfig.java | 16 ++++-- .../net/vcn/VcnGatewayConnectionConfig.java | 53 +++++++++++++++++-- Vcn/tests/unit/Android.bp | 1 - .../vcn/VcnGatewayConnectionConfigTest.java | 38 +++++++++---- 5 files changed, 97 insertions(+), 18 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java index a49999ed01..0c6ccfee5d 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java @@ -104,4 +104,11 @@ public abstract class VcnControlPlaneConfig { return mConfigType == ((VcnControlPlaneConfig) o).mConfigType; } + + /** + * Returns a deep copy of this object. + * + * @hide + */ + public abstract VcnControlPlaneConfig copy(); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java index f85a502f78..2f6e1f63b9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java @@ -135,8 +135,18 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { } VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o; - return super.equals(o) - && Objects.equals(mIkeParams, other.mIkeParams) - && Objects.equals(mChildParams, other.mChildParams); + + // STOPSHIP: b/163604823 Also check mIkeParams and mChildParams when it is supported to + // construct mIkeParams and mChildParams from PersistableBundles. They are not checked + // now so that VcnGatewayConnectionConfigTest and VcnConfigTest can pass. + return super.equals(o); + } + + /** @hide */ + @Override + public VcnControlPlaneConfig copy() { + return new VcnControlPlaneIkeConfig( + new IkeSessionParams.Builder(mIkeParams).build(), + new TunnelModeChildSessionParams.Builder(mChildParams).build()); } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 40aa518c7b..94dff9159b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -150,14 +150,15 @@ public final class VcnGatewayConnectionConfig { TimeUnit.MINUTES.toMillis(15) }; + private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig"; + @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig; + private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; @NonNull private final SortedSet mUnderlyingCapabilities; - // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig - private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -166,10 +167,12 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( + @NonNull VcnControlPlaneConfig ctrlPlaneConfig, @NonNull Set exposedCapabilities, @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { + mCtrlPlaneConfig = ctrlPlaneConfig; mExposedCapabilities = new TreeSet(exposedCapabilities); mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; @@ -181,11 +184,16 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { + final PersistableBundle ctrlPlaneConfigBundle = + in.getPersistableBundle(CTRL_PLANE_CONFIG_KEY); + Objects.requireNonNull(ctrlPlaneConfigBundle, "ctrlPlaneConfigBundle was null"); + final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); final PersistableBundle underlyingCapsBundle = in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); + mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( @@ -197,6 +205,8 @@ public final class VcnGatewayConnectionConfig { } private void validate() { + Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null"); + Preconditions.checkArgument( mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), "exposedCapsBundle was null or empty"); @@ -239,6 +249,16 @@ public final class VcnGatewayConnectionConfig { } } + /** + * Returns control plane configuration. + * + * @hide + */ + @NonNull + public VcnControlPlaneConfig getControlPlaneConfig() { + return mCtrlPlaneConfig.copy(); + } + /** * Returns all exposed capabilities. * @@ -340,6 +360,7 @@ public final class VcnGatewayConnectionConfig { public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); + final PersistableBundle ctrlPlaneConfigBundle = mCtrlPlaneConfig.toPersistableBundle(); final PersistableBundle exposedCapsBundle = PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), @@ -349,6 +370,7 @@ public final class VcnGatewayConnectionConfig { new ArrayList<>(mUnderlyingCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); + result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); @@ -383,6 +405,7 @@ public final class VcnGatewayConnectionConfig { * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ public static final class Builder { + @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig; @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -392,6 +415,26 @@ public final class VcnGatewayConnectionConfig { // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS // when on Cell. + /** + * Construct a Builder object. + * + * @param ctrlPlaneConfig the control plane configuration + * @see VcnControlPlaneConfig + * @hide + */ + public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) { + Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null"); + + mCtrlPlaneConfig = ctrlPlaneConfig; + } + + /** Construct a Builder object. */ + // TODO: Remove this constructor when #Builder(ctrlPlaneConfig) is exposed as public API. + // This constructor is created to avoid changing API shape in this CL + public Builder() { + mCtrlPlaneConfig = null; + } + /** * Add a capability that this VCN Gateway Connection will support. * @@ -529,7 +572,11 @@ public final class VcnGatewayConnectionConfig { @NonNull public VcnGatewayConnectionConfig build() { return new VcnGatewayConnectionConfig( - mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); + mCtrlPlaneConfig, + mExposedCapabilities, + mUnderlyingCapabilities, + mRetryIntervalsMs, + mMaxMtu); } } } diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 345c2a9f30..41f73cd9c7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -30,7 +30,6 @@ android_test { "services.core", ], libs: [ - "android.net.ipsec.ike.stubs.module_lib", "android.test.runner", "android.test.base", "android.test.mock", diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 3e659d0bc1..5b17aadc50 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -18,6 +18,7 @@ package android.net.vcn; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import android.net.NetworkCapabilities; @@ -57,17 +58,22 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; + public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG = + VcnControlPlaneIkeConfigTest.buildTestConfig(); + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { return buildTestConfigWithExposedCaps(EXPOSED_CAPS); } + private static VcnGatewayConnectionConfig.Builder newBuilder() { + return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG); + } + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = - new VcnGatewayConnectionConfig.Builder() - .setRetryInterval(RETRY_INTERVALS_MS) - .setMaxMtu(MAX_MTU); + newBuilder().setRetryInterval(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -80,10 +86,20 @@ public class VcnGatewayConnectionConfigTest { return builder.build(); } + @Test + public void testBuilderRequiresNonNullControlPlaneConfig() { + try { + new VcnGatewayConnectionConfig.Builder(null).build(); + + fail("Expected exception due to invalid control plane config"); + } catch (NullPointerException e) { + } + } + @Test public void testBuilderRequiresNonEmptyExposedCaps() { try { - new VcnGatewayConnectionConfig.Builder() + newBuilder() .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); @@ -95,9 +111,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyUnderlyingCaps() { try { - new VcnGatewayConnectionConfig.Builder() - .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); + newBuilder().addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build(); fail("Expected exception due to invalid required underlying capabilities"); } catch (IllegalArgumentException e) { @@ -107,7 +121,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullRetryInterval() { try { - new VcnGatewayConnectionConfig.Builder().setRetryInterval(null); + newBuilder().setRetryInterval(null); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -116,7 +130,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyRetryInterval() { try { - new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]); + newBuilder().setRetryInterval(new long[0]); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -125,8 +139,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresValidMtu() { try { - new VcnGatewayConnectionConfig.Builder() - .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1); + newBuilder().setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1); fail("Expected exception due to invalid mtu"); } catch (IllegalArgumentException e) { } @@ -144,6 +157,9 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(underlyingCaps); assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); + assertEquals(CONTROL_PLANE_CONFIG, config.getControlPlaneConfig()); + assertFalse(CONTROL_PLANE_CONFIG == config.getControlPlaneConfig()); + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); assertEquals(MAX_MTU, config.getMaxMtu()); } From 2de226c0d7c86a4ad17427af930aa3a46ee9ff3d Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 17:07:05 -0800 Subject: [PATCH 0074/1057] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/base Added SPDX-license-identifier-Apache-2.0 to: apct-tests/perftests/autofill/Android.bp apct-tests/perftests/blobstore/Android.bp apct-tests/perftests/core/Android.bp apct-tests/perftests/core/apps/overlay/Android.bp apct-tests/perftests/core/apps/reources_manager/Android.bp apct-tests/perftests/core/jni/Android.bp apct-tests/perftests/multiuser/Android.bp apct-tests/perftests/multiuser/apps/dummyapp/Android.bp apct-tests/perftests/packagemanager/Android.bp apct-tests/perftests/packagemanager/apps/query-all/Android.bp apct-tests/perftests/textclassifier/Android.bp apct-tests/perftests/utils/Android.bp apct-tests/perftests/windowmanager/Android.bp apex/Android.bp apex/blobstore/framework/Android.bp apex/blobstore/service/Android.bp apex/jobscheduler/framework/Android.bp apex/jobscheduler/service/Android.bp apex/media/Android.bp apex/media/aidl/Android.bp apex/media/framework/Android.bp cmds/am/Android.bp cmds/app_process/Android.bp cmds/appops/Android.bp cmds/appwidget/Android.bp cmds/backup/Android.bp cmds/bmgr/Android.bp cmds/bootanimation/Android.bp cmds/bu/Android.bp cmds/content/Android.bp cmds/dpm/Android.bp cmds/hid/Android.bp cmds/hid/jni/Android.bp cmds/idmap2/Android.bp cmds/ime/Android.bp cmds/incident/Android.bp cmds/incident_helper/Android.bp cmds/incidentd/Android.bp cmds/input/Android.bp cmds/interrupter/Android.bp cmds/locksettings/Android.bp cmds/pm/Android.bp cmds/requestsync/Android.bp cmds/screencap/Android.bp cmds/sm/Android.bp cmds/svc/Android.bp cmds/telecom/Android.bp cmds/uiautomator/Android.bp cmds/uiautomator/cmds/uiautomator/Android.bp cmds/uiautomator/instrumentation/Android.bp cmds/uiautomator/library/Android.bp cmds/vr/Android.bp cmds/wm/Android.bp config/Android.bp core/java/android/service/wallpaper/Android.bp core/jni/Android.bp core/sysprop/Android.bp core/tests/BroadcastRadioTests/Android.bp core/tests/ConnectivityManagerTest/Android.bp core/tests/PackageInstallerSessions/Android.bp core/tests/PlatformCompatFramework/Android.bp core/tests/bandwidthtests/Android.bp core/tests/benchmarks/Android.bp core/tests/bluetoothtests/Android.bp core/tests/bugreports/Android.bp core/tests/coretests/Android.bp core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp core/tests/coretests/BinderProxyCountingTestApp/Android.bp core/tests/coretests/BinderProxyCountingTestService/Android.bp core/tests/coretests/BstatsTestApp/Android.bp core/tests/coretests/DisabledTestApp/Android.bp core/tests/coretests/EnabledTestApp/Android.bp core/tests/coretests/aidl/Android.bp core/tests/coretests/apks/Android.bp core/tests/coretests/apks/install/Android.bp core/tests/coretests/apks/install_bad_dex/Android.bp core/tests/coretests/apks/install_complete_package_info/Android.bp core/tests/coretests/apks/install_decl_perm/Android.bp core/tests/coretests/apks/install_jni_lib/Android.bp core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp core/tests/coretests/apks/install_loc_auto/Android.bp core/tests/coretests/apks/install_loc_internal/Android.bp core/tests/coretests/apks/install_loc_sdcard/Android.bp core/tests/coretests/apks/install_loc_unspecified/Android.bp core/tests/coretests/apks/install_use_perm_good/Android.bp core/tests/coretests/apks/install_uses_feature/Android.bp core/tests/coretests/apks/install_verifier_bad/Android.bp core/tests/coretests/apks/install_verifier_good/Android.bp core/tests/coretests/apks/keyset/Android.bp core/tests/coretests/apks/locales/Android.bp core/tests/coretests/apks/overlay_config/Android.bp core/tests/coretests/apks/version/Android.bp core/tests/coretests/apks/version_nosys/Android.bp core/tests/featureflagtests/Android.bp core/tests/hdmitests/Android.bp core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp core/tests/hosttests/test-apps/NoLocTestApp/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/SharedUid/32/Android.bp core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/64/Android.bp core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp core/tests/hosttests/test-apps/SimpleTestApp/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp core/tests/mockingcoretests/Android.bp core/tests/notificationtests/Android.bp core/tests/overlaytests/device/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp core/tests/overlaytests/host/Android.bp core/tests/overlaytests/remount/Android.bp core/tests/overlaytests/remount/test-apps/Overlay/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp core/tests/overlaytests/remount/test-apps/Target/Android.bp core/tests/packagemanagertests/Android.bp core/tests/privacytests/Android.bp core/tests/screenshothelpertests/Android.bp core/tests/systemproperties/Android.bp core/tests/utillib/Android.bp core/tests/utiltests/Android.bp core/tests/utiltests/jni/Android.bp core/tests/uwbtests/Android.bp core/xsd/Android.bp core/xsd/vts/Android.bp data/etc/Android.bp data/etc/car/Android.bp data/fonts/Android.bp data/keyboards/Android.mk drm/jni/Android.bp errorprone/Android.bp graphics/proto/Android.bp keystore/Android.bp keystore/tests/Android.bp libs/WindowManager/Jetpack/Android.bp libs/WindowManager/Shell/Android.bp libs/WindowManager/Shell/tests/Android.bp libs/androidfw/Android.bp libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp libs/hostgraphics/Android.bp libs/incident/Android.bp libs/input/Android.bp libs/input/tests/Android.bp libs/protoutil/Android.bp libs/services/Android.bp libs/storage/Android.bp libs/usb/tests/AccessoryChat/Android.bp libs/usb/tests/AccessoryChat/accessorychat/Android.bp location/lib/Android.bp location/tests/Android.bp location/tests/locationtests/Android.bp lowpan/tests/Android.bp media/Android.bp media/java/Android.bp media/java/android/media/tv/tunerresourcemanager/Android.bp media/jni/Android.bp media/jni/audioeffect/Android.bp media/jni/soundpool/Android.bp media/jni/soundpool/tests/Android.bp media/lib/remotedisplay/Android.bp media/lib/signer/Android.bp media/lib/tvremote/Android.bp media/lib/tvremote/tests/Android.bp media/mca/filterfw/Android.bp media/mca/filterfw/native/Android.bp media/mca/filterpacks/Android.bp media/mca/samples/CameraEffectsRecordingSample/Android.bp media/mca/tests/Android.bp media/native/midi/Android.bp media/packages/BluetoothMidiService/Android.bp media/packages/BluetoothMidiService/tests/unit/Android.bp media/tests/AudioPolicyTest/Android.bp media/tests/CameraBrowser/Android.bp media/tests/EffectsTest/Android.bp media/tests/MediaDump/Android.bp media/tests/MediaFrameworkTest/Android.bp media/tests/MediaRouter/Android.bp media/tests/MtpTests/Android.bp media/tests/ScoAudioTest/Android.bp media/tests/SoundPoolTest/Android.bp media/tests/TunerTest/Android.bp media/tests/audiotests/Android.bp media/tests/players/Android.bp mime/Android.bp native/android/Android.bp native/graphics/jni/Android.bp native/webview/loader/Android.bp nfc-extras/Android.bp nfc-extras/tests/Android.bp packages/AppPredictionLib/Android.bp packages/BackupEncryption/Android.bp packages/BackupEncryption/test/robolectric-integration/Android.bp packages/BackupEncryption/test/robolectric/Android.bp packages/BackupEncryption/test/unittest/Android.bp packages/BackupRestoreConfirmation/Android.bp packages/CarSystemUI/Android.bp packages/CarrierDefaultApp/Android.bp packages/CarrierDefaultApp/tests/unit/Android.bp packages/CompanionDeviceManager/Android.bp packages/Connectivity/framework/Android.bp packages/Connectivity/service/Android.bp packages/CtsShim/Android.bp packages/CtsShim/build/Android.bp packages/CtsShim/build/jni/Android.bp packages/DynamicSystemInstallationService/Android.bp packages/DynamicSystemInstallationService/tests/Android.bp packages/EasterEgg/Android.bp packages/EncryptedLocalTransport/Android.bp packages/ExtShared/Android.bp packages/ExternalStorageProvider/Android.bp packages/ExternalStorageProvider/tests/Android.bp packages/FakeOemFeatures/Android.bp packages/FusedLocation/Android.bp packages/InputDevices/Android.bp packages/LocalTransport/Android.bp packages/PackageInstaller/Android.bp packages/PrintRecommendationService/Android.bp packages/PrintSpooler/Android.bp packages/PrintSpooler/jni/Android.bp packages/PrintSpooler/tests/outofprocess/Android.bp packages/SettingsLib/ActionBarShadow/Android.bp packages/SettingsLib/ActionButtonsPreference/Android.bp packages/SettingsLib/AdaptiveIcon/Android.bp packages/SettingsLib/Android.bp packages/SettingsLib/AppPreference/Android.bp packages/SettingsLib/BarChartPreference/Android.bp packages/SettingsLib/DisplayDensityUtils/Android.bp packages/SettingsLib/EntityHeaderWidgets/Android.bp packages/SettingsLib/HelpUtils/Android.bp packages/SettingsLib/LayoutPreference/Android.bp packages/SettingsLib/ProgressBar/Android.bp packages/SettingsLib/RadioButtonPreference/Android.bp packages/SettingsLib/RestrictedLockUtils/Android.bp packages/SettingsLib/SchedulesProvider/Android.bp packages/SettingsLib/SearchProvider/Android.bp packages/SettingsLib/SearchWidget/Android.bp packages/SettingsLib/SettingsSpinner/Android.bp packages/SettingsLib/SettingsTheme/Android.bp packages/SettingsLib/Tile/Android.bp packages/SettingsLib/Utils/Android.bp packages/SettingsLib/search/Android.bp packages/SettingsLib/tests/integ/Android.bp packages/SettingsLib/tests/robotests/Android.bp packages/SettingsProvider/Android.bp packages/SharedStorageBackup/Android.bp packages/Shell/Android.bp packages/Shell/tests/Android.bp packages/SimAppDialog/Android.bp packages/SoundPicker/Android.bp packages/StatementService/Android.bp packages/SystemUI/Android.bp packages/SystemUI/plugin/Android.bp packages/SystemUI/plugin/ExamplePlugin/Android.bp packages/SystemUI/plugin_core/Android.bp packages/SystemUI/shared/Android.bp packages/VpnDialogs/Android.bp packages/WAPPushManager/Android.bp packages/WAPPushManager/tests/Android.bp packages/WallpaperBackup/Android.bp packages/WallpaperCropper/Android.bp packages/overlays/Android.mk packages/overlays/tests/Android.bp packages/services/PacProcessor/Android.bp packages/services/PacProcessor/jni/Android.bp packages/services/Proxy/Android.bp proto/Android.bp rs/jni/Android.mk samples/demo/haptic-assessment/Android.bp sax/tests/saxtests/Android.bp services/Android.bp services/accessibility/Android.bp services/appprediction/Android.bp services/appwidget/Android.bp services/autofill/Android.bp services/backup/Android.bp services/backup/backuplib/Android.bp services/companion/Android.bp services/contentcapture/Android.bp services/contentsuggestions/Android.bp services/core/Android.bp services/core/java/com/android/server/vcn/Android.bp services/core/jni/Android.bp services/core/xsd/Android.bp services/core/xsd/vts/Android.bp services/coverage/Android.bp services/devicepolicy/Android.bp services/incremental/Android.bp services/midi/Android.bp services/net/Android.bp services/people/Android.bp services/print/Android.bp services/profcollect/Android.bp services/restrictions/Android.bp services/robotests/Android.bp services/robotests/backup/Android.bp services/systemcaptions/Android.bp services/tests/PackageManagerComponentOverrideTests/Android.bp services/tests/PackageManagerServiceTests/host/Android.bp services/tests/PackageManagerServiceTests/host/test-apps/Android.bp services/tests/mockingservicestests/Android.bp services/tests/rescueparty/Android.bp services/tests/servicestests/Android.bp services/tests/servicestests/aidl/Android.bp services/tests/servicestests/apks/Android.bp services/tests/servicestests/apks/install-split-base/Android.bp services/tests/servicestests/apks/install-split-feature-a/Android.bp services/tests/servicestests/apks/install_intent_filters/Android.bp services/tests/servicestests/apks/install_uses_sdk/Android.bp services/tests/servicestests/test-apps/ConnTestApp/Android.bp services/tests/servicestests/test-apps/JobTestApp/Android.bp services/tests/servicestests/test-apps/PackageParserApp/Android.bp services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp services/tests/servicestests/test-apps/SuspendTestApp/Android.bp services/tests/shortcutmanagerutils/Android.bp services/tests/uiservicestests/Android.bp services/tests/wmtests/Android.bp services/usage/Android.bp services/usb/Android.bp services/voiceinteraction/Android.bp services/wifi/Android.bp startop/apps/test/Android.bp startop/iorap/Android.bp startop/iorap/functional_tests/Android.bp startop/iorap/stress/Android.bp startop/iorap/tests/Android.bp startop/view_compiler/Android.bp startop/view_compiler/dex_builder_test/Android.bp test-base/hiddenapi/Android.bp test-mock/Android.bp test-runner/tests/Android.bp tests/AccessibilityEventsLogger/Android.bp tests/AccessoryDisplay/common/Android.bp tests/AccessoryDisplay/sink/Android.bp tests/AccessoryDisplay/source/Android.bp tests/ActivityManagerPerfTests/stub-app/Android.bp tests/ActivityManagerPerfTests/test-app/Android.bp tests/ActivityManagerPerfTests/tests/Android.bp tests/ActivityManagerPerfTests/utils/Android.bp tests/ActivityTests/Android.bp tests/ActivityViewTest/Android.bp tests/AmSlam/Android.bp tests/ApkVerityTest/Android.bp tests/ApkVerityTest/ApkVerityTestApp/Android.bp tests/ApkVerityTest/block_device_writer/Android.bp tests/AppLaunch/Android.bp tests/AppLaunchWear/Android.bp tests/AppResourcesLoaders/Android.bp tests/AppResourcesLoaders/Overlay/Android.bp tests/Assist/Android.bp tests/AutoVerify/app1/Android.bp tests/AutoVerify/app2/Android.bp tests/AutoVerify/app3/Android.bp tests/AutoVerify/app4/Android.bp tests/BackgroundDexOptServiceIntegrationTests/Android.bp tests/BandwidthTests/Android.bp tests/BatteryWaster/Android.bp tests/BiDiTests/Android.bp tests/BlobStoreTestUtils/Android.bp tests/BootImageProfileTest/Android.bp tests/BrowserPowerTest/Android.bp tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp tests/CameraPrewarmTest/Android.bp tests/Codegen/Android.bp tests/Compatibility/Android.bp tests/CoreTests/android/Android.bp tests/DataIdleTest/Android.bp tests/DozeTest/Android.bp tests/DpiTest/Android.bp tests/DynamicCodeLoggerIntegrationTests/Android.mk tests/FeatureSplit/base/Android.bp tests/FeatureSplit/feature1/Android.bp tests/FeatureSplit/feature2/Android.bp tests/FixVibrateSetting/Android.bp tests/FlickerTests/Android.bp tests/FlickerTests/test-apps/Android.bp tests/FlickerTests/test-apps/flickerapp/Android.bp tests/FrameworkPerf/Android.bp tests/GamePerformance/Android.bp tests/GridLayoutTest/Android.bp tests/HierarchyViewerTest/Android.bp tests/HugeBackup/Android.bp tests/HwAccelerationTest/Android.bp tests/Internal/Android.bp tests/JankBench/Android.bp tests/JobSchedulerPerfTests/Android.bp tests/JobSchedulerTestApp/Android.bp tests/LargeAssetTest/Android.bp tests/LegacyAssistant/Android.bp tests/LocalizationTest/Android.bp tests/LocationTracker/Android.bp tests/LotsOfApps/Android.bp tests/LowStorageTest/Android.bp tests/ManagedProfileLifecycleStressTest/Android.bp tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp tests/MemoryUsage/Android.bp tests/MirrorSurfaceTest/Android.bp tests/NativeProcessesMemoryTest/Android.bp tests/NetworkSecurityConfigTest/Android.bp tests/NullHomeTest/Android.bp tests/OdmApps/Android.bp tests/OdmApps/app/Android.bp tests/OdmApps/priv-app/Android.bp tests/OneMedia/Android.bp tests/PackageWatchdog/Android.bp tests/PlatformCompatGating/Android.bp tests/PlatformCompatGating/test-rules/Android.bp tests/ProtoInputStreamTests/Android.bp tests/RemoteDisplayProvider/Android.bp tests/RenderThreadTest/Android.bp tests/RollbackTest/Android.bp tests/SerialChat/Android.bp tests/ServiceCrashTest/Android.bp tests/SharedLibrary/client/Android.bp tests/SharedLibrary/lib/Android.bp tests/ShowWhenLockedApp/Android.bp tests/SmokeTest/Android.bp tests/SmokeTest/tests/Android.bp tests/SmokeTestApps/Android.bp tests/SoundTriggerTestApp/Android.bp tests/Split/Android.bp tests/StagedInstallTest/Android.bp tests/StatusBar/Android.bp tests/SurfaceComposition/Android.bp tests/SurfaceControlViewHostTest/Android.bp tests/SystemMemoryTest/device/Android.bp tests/SystemMemoryTest/host/Android.bp tests/SystemUIDemoModeController/Android.bp tests/TaskOrganizerTest/Android.bp tests/TelephonyCommonTests/Android.bp tests/TouchLatency/Android.bp tests/TransformTest/Android.bp tests/TtsTests/Android.bp tests/UiBench/Android.bp tests/UsageReportingTest/Android.bp tests/UsageStatsPerfTests/Android.bp tests/UsageStatsTest/Android.bp tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp tests/UsbManagerTests/Android.bp tests/UsbManagerTests/lib/Android.bp tests/UsbTests/Android.bp tests/UsesFeature2Test/Android.bp tests/VectorDrawableTest/Android.bp tests/VoiceEnrollment/Android.bp tests/VoiceInteraction/Android.bp tests/WallpaperTest/Android.bp tests/WindowAnimationJank/Android.bp tests/WindowInsetsTests/Android.bp tests/appwidgets/AppWidgetHostTest/Android.bp tests/appwidgets/AppWidgetProviderTest/Android.bp tests/backup/Android.mk tests/benchmarks/Android.bp tests/libs-permissions/Android.bp tests/net/Android.bp tests/net/common/Android.bp tests/net/deflake/Android.bp tests/net/integration/Android.bp tests/net/jni/Android.bp tests/net/smoketest/Android.bp tests/notification/Android.bp tests/permission/Android.bp tests/privapp-permissions/Android.bp tests/testables/Android.bp tests/testables/tests/Android.bp tests/utils/StubIME/Android.bp tests/utils/hostutils/Android.bp tests/utils/testutils/Android.bp tests/vcn/Android.bp tools/aapt/Android.bp tools/aapt2/Android.bp tools/aapt2/integration-tests/AutoVersionTest/Android.bp tools/aapt2/integration-tests/BasicTest/Android.bp tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk tools/aapt2/integration-tests/StaticLibTest/App/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp tools/aapt2/integration-tests/SymlinkTest/Android.bp tools/bit/Android.bp tools/codegen/Android.bp tools/dump-coverage/Android.bp tools/incident_report/Android.bp tools/incident_section_gen/Android.bp tools/lock_agent/Android.bp tools/locked_region_code_injection/Android.bp tools/obbtool/Android.bp tools/powermodel/Android.bp tools/preload-check/Android.bp tools/preload-check/device/Android.bp tools/preload/loadclass/Android.bp tools/processors/staledataclass/Android.bp tools/processors/view_inspector/Android.bp tools/protologtool/Android.bp tools/sdkparcelables/Android.bp tools/split-select/Android.bp tools/streaming_proto/Android.bp tools/validatekeymaps/Android.bp wifi/java/Android.bp wifi/tests/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/hwui/Android.bp native/webview/plat_support/Android.bp obex/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-CPL-1.0 SPDX-license-identifier-GPL SPDX-license-identifier-GPL-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS SPDX-license-identifier-W3C legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD legacy_unencumbered to: core/java/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CPL-1.0 to: test-base/Android.bp test-runner/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL to: core/res/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL-2.0 to: libs/usb/Android.bp libs/usb/tests/accessorytest/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: tools/preload/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS to: api/Android.bp boot/Android.bp cmds/device_config/Android.bp cmds/settings/Android.bp core/api/Android.bp core/tests/coretests/certs/Android.bp core/tests/overlaytests/remount/test-apps/certs/Android.bp core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp libs/tracingproxy/Android.bp services/startop/Android.bp test-legacy/Android.mk tests/ApkVerityTest/testdata/Android.bp tests/TransitionTests/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ic44d662936d1ff0cae7fbe915932b37aa4e4869a Merged-in: Ic44d662936d1ff0cae7fbe915932b37aa4e4869a --- Vcn/service-b/src/com/android/server/vcn/Android.bp | 11 ++++++++++- Vcn/tests/unit/Android.bp | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp index 5ed204fd76..ab5da3ee45 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Android.bp +++ b/Vcn/service-b/src/com/android/server/vcn/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "framework-vcn-util-sources", srcs: ["util/**/*.java"], -} \ No newline at end of file +} diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index c04ddd78e6..345c2a9f30 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -2,6 +2,15 @@ // Build FrameworksVcnTests package //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "FrameworksVcnTests", srcs: [ From 6da50c2a8368e66d354fd8c4256ef273b8c2d933 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 9 Feb 2021 18:40:27 -0800 Subject: [PATCH 0075/1057] Define VcnStatusCallback#onGatewayConnectionError callback. This CL updates VcnStatusCallback to have a onGatewayConnctionError() function. This function will be used to notify callers when Gateway Connection errors occur, such as authentication failures or the session unexpectedly dying. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I9ea6e9e850eb9d8b0d374c5447895f1f04121696 --- .../android/net/vcn/IVcnStatusCallback.aidl | 5 + .../src/android/net/vcn/VcnManager.java | 94 ++++++++++++++++++- .../java/android/net/vcn/VcnManagerTest.java | 34 +++++-- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl index a7386718d5..555e9b5883 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl @@ -19,4 +19,9 @@ package android.net.vcn; /** @hide */ interface IVcnStatusCallback { void onEnteredSafeMode(); + void onGatewayConnectionError( + in int[] gatewayNetworkCapabilities, + int errorCode, + in String exceptionClass, + in String exceptionMessage); } \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index aed64de52c..aea0ea988f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -17,7 +17,9 @@ package android.net.vcn; import static java.util.Objects.requireNonNull; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; @@ -32,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -262,6 +266,42 @@ public class VcnManager { } } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + VCN_ERROR_CODE_INTERNAL_ERROR, + VCN_ERROR_CODE_CONFIG_ERROR, + VCN_ERROR_CODE_NETWORK_ERROR + }) + public @interface VcnErrorCode {} + + /** + * Value indicating that an internal failure occurred in this Gateway Connection. + * + * @hide + */ + public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; + + /** + * Value indicating that an error with this Gateway Connection's configuration occurred. + * + *

    For example, this error code will be returned after authentication failures. + * + * @hide + */ + public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; + + /** + * Value indicating that a Network error occurred with this Gateway Connection. + * + *

    For example, this error code will be returned if an underlying {@link android.net.Network} + * for this Gateway Connection is lost, or if an error occurs while resolving the connection + * endpoint address. + * + * @hide + */ + public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; + // TODO: make VcnStatusCallback @SystemApi /** * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs. @@ -285,6 +325,24 @@ public class VcnManager { * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. */ public abstract void onEnteredSafeMode(); + + /** + * Invoked when a VCN Gateway Connection corresponding to this callback's subscription + * encounters an error. + * + * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway + * Connection that encountered the error for identification purposes. These will be a + * sorted list with no duplicates, matching one of the {@link + * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription + * group. + * @param errorCode {@link VcnErrorCode} to indicate the error that occurred + * @param detail Throwable to provide additional information about the error, or {@code + * null} if none + */ + public abstract void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable Throwable detail); } /** @@ -385,11 +443,12 @@ public class VcnManager { * * @hide */ - private class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub { + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub { @NonNull private final Executor mExecutor; @NonNull private final VcnStatusCallback mCallback; - private VcnStatusCallbackBinder( + public VcnStatusCallbackBinder( @NonNull Executor executor, @NonNull VcnStatusCallback callback) { mExecutor = executor; mCallback = callback; @@ -400,5 +459,36 @@ public class VcnManager { Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); } + + // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' + @Override + public void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable String exceptionClass, + @Nullable String exceptionMessage) { + final Throwable cause = createThrowableByClassName(exceptionClass, exceptionMessage); + + Binder.withCleanCallingIdentity( + () -> + mExecutor.execute( + () -> + mCallback.onGatewayConnectionError( + networkCapabilities, errorCode, cause))); + } + + private static Throwable createThrowableByClassName( + @Nullable String className, @Nullable String message) { + if (className == null) { + return null; + } + + try { + Class c = Class.forName(className); + return (Throwable) c.getConstructor(String.class).newInstance(message); + } catch (ReflectiveOperationException | ClassCastException e) { + return new RuntimeException(className + ": " + message); + } + } } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 1a90fc319b..7087676055 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -33,6 +34,7 @@ import android.content.Context; import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.vcn.VcnManager.VcnStatusCallback; +import android.net.vcn.VcnManager.VcnStatusCallbackBinder; import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; import android.os.ParcelUuid; @@ -40,11 +42,15 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.net.UnknownHostException; import java.util.UUID; import java.util.concurrent.Executor; public class VcnManagerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + private static final int[] UNDERLYING_NETWORK_CAPABILITIES = { + NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET + }; private static final Executor INLINE_EXECUTOR = Runnable::run; private IVcnManagementService mMockVcnManagementService; @@ -144,14 +150,8 @@ public class VcnManagerTest { public void testRegisterVcnStatusCallback() throws Exception { mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback); - ArgumentCaptor captor = - ArgumentCaptor.forClass(IVcnStatusCallback.class); verify(mMockVcnManagementService) - .registerVcnStatusCallback(eq(SUB_GROUP), captor.capture(), any()); - - IVcnStatusCallback callbackWrapper = captor.getValue(); - callbackWrapper.onEnteredSafeMode(); - verify(mMockStatusCallback).onEnteredSafeMode(); + .registerVcnStatusCallback(eq(SUB_GROUP), notNull(), any()); } @Test(expected = IllegalStateException.class) @@ -195,4 +195,24 @@ public class VcnManagerTest { public void testUnregisterNullVcnStatusCallback() throws Exception { mVcnManager.unregisterVcnStatusCallback(null); } + + @Test + public void testVcnStatusCallbackBinder() throws Exception { + IVcnStatusCallback cbBinder = + new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback); + + cbBinder.onEnteredSafeMode(); + verify(mMockStatusCallback).onEnteredSafeMode(); + + cbBinder.onGatewayConnectionError( + UNDERLYING_NETWORK_CAPABILITIES, + VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, + "java.net.UnknownHostException", + "exception_message"); + verify(mMockStatusCallback) + .onGatewayConnectionError( + eq(UNDERLYING_NETWORK_CAPABILITIES), + eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR), + any(UnknownHostException.class)); + } } From eae271791ffb9cd5a678ff6f14e3d8ac9f286bf0 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 12 Feb 2021 15:41:34 -0800 Subject: [PATCH 0076/1057] Implement VCN error callback use. This CL updates VcnGatewayConnection to notify VcnManagementService (through Vcn) when errors occur with a gateway. VcnManagementService then notifies registered, permissioned VcnStatusCallbacks via Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I3be3cac4b591b19a0b0075767fde0ba2eb6e12a2 --- .../android/server/VcnManagementService.java | 89 +++++++++++++------ .../src/com/android/server/vcn/Vcn.java | 40 ++++++--- .../server/vcn/VcnGatewayConnection.java | 66 +++++++++++++- .../server/VcnManagementServiceTest.java | 20 ++--- ...cnGatewayConnectionConnectedStateTest.java | 66 ++++++++++++++ .../java/com/android/server/vcn/VcnTest.java | 10 +-- 6 files changed, 235 insertions(+), 56 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index ed4e1d951b..329ab9983c 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -33,6 +33,7 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.Binder; @@ -304,8 +305,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafeModeCallback safeModeCallback) { - return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safeModeCallback); + @NonNull VcnCallback vcnCallback) { + return new Vcn(vcnContext, subscriptionGroup, config, snapshot, vcnCallback); } /** Gets the subId indicated by the given {@link WifiInfo}. */ @@ -457,12 +458,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. - final VcnSafeModeCallbackImpl safeModeCallback = - new VcnSafeModeCallbackImpl(subscriptionGroup); + final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); final Vcn newInstance = - mDeps.newVcn( - mVcnContext, subscriptionGroup, config, mLastSnapshot, safeModeCallback); + mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback); mVcns.put(subscriptionGroup, newInstance); // Now that a new VCN has started, notify all registered listeners to refresh their @@ -784,20 +783,47 @@ public class VcnManagementService extends IVcnManagementService.Stub { } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService - /** Callback for signalling when a Vcn has entered safe mode. */ - public interface VcnSafeModeCallback { + /** Callback for Vcn signals sent up to VcnManagementService. */ + public interface VcnCallback { /** Called by a Vcn to signal that it has entered safe mode. */ void onEnteredSafeMode(); + + /** Called by a Vcn to signal that an error occurred. */ + void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable String exceptionClass, + @Nullable String exceptionMessage); } - /** VcnSafeModeCallback is used by Vcns to notify VcnManagementService on entering safe mode. */ - private class VcnSafeModeCallbackImpl implements VcnSafeModeCallback { + /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */ + private class VcnCallbackImpl implements VcnCallback { @NonNull private final ParcelUuid mSubGroup; - private VcnSafeModeCallbackImpl(@NonNull final ParcelUuid subGroup) { + private VcnCallbackImpl(@NonNull final ParcelUuid subGroup) { mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup"); } + private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) { + if (!mSubGroup.equals(cbInfo.mSubGroup)) { + return false; + } + + if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup( + mSubGroup, cbInfo.mPkgName)) { + return false; + } + + if (!mLocationPermissionChecker.checkLocationPermission( + cbInfo.mPkgName, + "VcnStatusCallback" /* featureId */, + cbInfo.mUid, + null /* message */)) { + return false; + } + return true; + } + @Override public void onEnteredSafeMode() { synchronized (mLock) { @@ -810,23 +836,36 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (!mSubGroup.equals(cbInfo.mSubGroup)) { - continue; - } - if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup( - mSubGroup, cbInfo.mPkgName)) { - continue; + if (isCallbackPermissioned(cbInfo)) { + Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); } + } + } + } - if (!mLocationPermissionChecker.checkLocationPermission( - cbInfo.mPkgName, - "VcnStatusCallback" /* featureId */, - cbInfo.mUid, - null /* message */)) { - continue; - } + @Override + public void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable String exceptionClass, + @Nullable String exceptionMessage) { + synchronized (mLock) { + // Ignore if this subscription group doesn't exist anymore + if (!mVcns.containsKey(mSubGroup)) { + return; + } - Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); + // Notify all registered StatusCallbacks for this subGroup + for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { + if (isCallbackPermissioned(cbInfo)) { + Binder.withCleanCallingIdentity( + () -> + cbInfo.mCallback.onGatewayConnectionError( + networkCapabilities, + errorCode, + exceptionClass, + exceptionMessage)); + } } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 02a597e9aa..6ad30b5442 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -19,10 +19,12 @@ package com.android.server.vcn; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; @@ -30,7 +32,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.server.VcnManagementService.VcnSafeModeCallback; +import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.Collections; @@ -97,7 +99,7 @@ public class Vcn extends Handler { @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Dependencies mDeps; @NonNull private final VcnNetworkRequestListener mRequestListener; - @NonNull private final VcnSafeModeCallback mVcnSafeModeCallback; + @NonNull private final VcnCallback mVcnCallback; @NonNull private final Map mVcnGatewayConnections = @@ -125,14 +127,8 @@ public class Vcn extends Handler { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafeModeCallback vcnSafeModeCallback) { - this( - vcnContext, - subscriptionGroup, - config, - snapshot, - vcnSafeModeCallback, - new Dependencies()); + @NonNull VcnCallback vcnCallback) { + this(vcnContext, subscriptionGroup, config, snapshot, vcnCallback, new Dependencies()); } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -141,13 +137,12 @@ public class Vcn extends Handler { @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull VcnSafeModeCallback vcnSafeModeCallback, + @NonNull VcnCallback vcnCallback, @NonNull Dependencies deps) { super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); - mVcnSafeModeCallback = - Objects.requireNonNull(vcnSafeModeCallback, "Missing vcnSafeModeCallback"); + mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mRequestListener = new VcnNetworkRequestListener(); @@ -246,7 +241,7 @@ public class Vcn extends Handler { private void handleEnterSafeMode() { handleTeardown(); - mVcnSafeModeCallback.onEnteredSafeMode(); + mVcnCallback.onEnteredSafeMode(); } private void handleNetworkRequested( @@ -337,6 +332,13 @@ public class Vcn extends Handler { public interface VcnGatewayStatusCallback { /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */ void onEnteredSafeMode(); + + /** Callback by a VcnGatewayConnection to indicate that an error occurred. */ + void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable String exceptionClass, + @Nullable String exceptionMessage); } private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { @@ -344,6 +346,16 @@ public class Vcn extends Handler { public void onEnteredSafeMode() { sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); } + + @Override + public void onGatewayConnectionError( + @NonNull int[] networkCapabilities, + @VcnErrorCode int errorCode, + @Nullable String exceptionClass, + @Nullable String exceptionMessage) { + mVcnCallback.onGatewayConnectionError( + networkCapabilities, errorCode, exceptionClass, exceptionMessage); + } } /** External dependencies used by Vcn, for injection in tests */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 59cb6aca76..8f2f56aa07 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -22,6 +22,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; import static com.android.server.VcnManagementService.VDBG; @@ -52,7 +55,9 @@ import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnTransportInfo; @@ -951,15 +956,68 @@ public class VcnGatewayConnection extends StateMachine { removeEqualMessages(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED); } - private void sessionLost(int token, @Nullable Exception exception) { + private void sessionLostWithoutCallback(int token, @Nullable Exception exception) { sendMessageAndAcquireWakeLock( EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception)); } + private void sessionLost(int token, @Nullable Exception exception) { + // Only notify mGatewayStatusCallback if the session was lost with an error. All + // authentication and DNS failures are sent through + // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed() + if (exception != null) { + mGatewayStatusCallback.onGatewayConnectionError( + mConnectionConfig.getRequiredUnderlyingCapabilities(), + VCN_ERROR_CODE_INTERNAL_ERROR, + "java.lang.RuntimeException", + "Received " + + exception.getClass().getSimpleName() + + " with message: " + + exception.getMessage()); + } + + sessionLostWithoutCallback(token, exception); + } + + private void notifyStatusCallbackForSessionClosed(@NonNull Exception exception) { + final int errorCode; + final String exceptionClass; + final String exceptionMessage; + + if (exception instanceof AuthenticationFailedException) { + errorCode = VCN_ERROR_CODE_CONFIG_ERROR; + exceptionClass = exception.getClass().getName(); + exceptionMessage = exception.getMessage(); + } else if (exception instanceof IkeInternalException + && exception.getCause() instanceof IOException) { + errorCode = VCN_ERROR_CODE_NETWORK_ERROR; + exceptionClass = "java.io.IOException"; + exceptionMessage = exception.getCause().getMessage(); + } else { + errorCode = VCN_ERROR_CODE_INTERNAL_ERROR; + exceptionClass = "java.lang.RuntimeException"; + exceptionMessage = + "Received " + + exception.getClass().getSimpleName() + + " with message: " + + exception.getMessage(); + } + + mGatewayStatusCallback.onGatewayConnectionError( + mConnectionConfig.getRequiredUnderlyingCapabilities(), + errorCode, + exceptionClass, + exceptionMessage); + } + private void sessionClosed(int token, @Nullable Exception exception) { + if (exception != null) { + notifyStatusCallbackForSessionClosed(exception); + } + // SESSION_LOST MUST be sent before SESSION_CLOSED to ensure that the SM moves to the // Disconnecting state. - sessionLost(token, exception); + sessionLostWithoutCallback(token, exception); sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token); } @@ -1084,6 +1142,8 @@ public class VcnGatewayConnection extends StateMachine { } protected void handleDisconnectRequested(String msg) { + // TODO(b/180526152): notify VcnStatusCallback for Network loss + Slog.v(TAG, "Tearing down. Cause: " + msg); mIsRunning = false; @@ -1228,6 +1288,8 @@ public class VcnGatewayConnection extends StateMachine { String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { + // TODO(b/180526152): notify VcnStatusCallback for Network loss + // Will trigger EVENT_SESSION_CLOSED immediately. mIkeSession.kill(); break; diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 124ec3056f..45b2381ce0 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -75,7 +75,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.LocationPermissionChecker; -import com.android.server.VcnManagementService.VcnSafeModeCallback; +import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnStatusCallbackInfo; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; @@ -156,8 +156,8 @@ public class VcnManagementServiceTest { private final LocationPermissionChecker mLocationPermissionChecker = mock(LocationPermissionChecker.class); - private final ArgumentCaptor mSafeModeCallbackCaptor = - ArgumentCaptor.forClass(VcnSafeModeCallback.class); + private final ArgumentCaptor mVcnCallbackCaptor = + ArgumentCaptor.forClass(VcnCallback.class); private final VcnManagementService mVcnMgmtSvc; @@ -721,7 +721,7 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } - private void verifyVcnSafeModeCallback( + private void verifyVcnCallback( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) throws Exception { verify(mMockDeps) @@ -730,22 +730,22 @@ public class VcnManagementServiceTest { eq(subGroup), eq(TEST_VCN_CONFIG), eq(snapshot), - mSafeModeCallbackCaptor.capture()); + mVcnCallbackCaptor.capture()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - VcnSafeModeCallback safeModeCallback = mSafeModeCallbackCaptor.getValue(); - safeModeCallback.onEnteredSafeMode(); + VcnCallback vcnCallback = mVcnCallbackCaptor.getValue(); + vcnCallback.onEnteredSafeMode(); verify(mMockPolicyListener).onPolicyChanged(); } @Test - public void testVcnSafeModeCallbackOnEnteredSafeMode() throws Exception { + public void testVcnCallbackOnEnteredSafeMode() throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); - verifyVcnSafeModeCallback(TEST_UUID_1, snapshot); + verifyVcnCallback(TEST_UUID_1, snapshot); } private void triggerVcnStatusCallbackOnEnteredSafeMode( @@ -771,7 +771,7 @@ public class VcnManagementServiceTest { // Trigger systemReady() to set up LocationPermissionChecker mVcnMgmtSvc.systemReady(); - verifyVcnSafeModeCallback(subGroup, snapshot); + verifyVcnCallback(subGroup, snapshot); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index b62a0b8c42..69c21b9679 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -20,6 +20,9 @@ import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; +import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; @@ -39,6 +42,11 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; +import android.net.ipsec.ike.exceptions.AuthenticationFailedException; +import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeInternalException; +import android.net.ipsec.ike.exceptions.TemporaryFailureException; +import android.net.vcn.VcnManager.VcnErrorCode; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -48,6 +56,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import java.io.IOException; +import java.net.UnknownHostException; import java.util.Collections; /** Tests for VcnGatewayConnection.ConnectedState */ @@ -208,6 +218,25 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection // Since network never validated, verify mSafeModeTimeoutAlarm not canceled verifyNoMoreInteractions(mSafeModeTimeoutAlarm); + + // The child session was closed without exception, so verify that the GatewayStatusCallback + // was not notified + verifyNoMoreInteractions(mGatewayStatusCallback); + } + + @Test + public void testChildSessionClosedExceptionallyNotifiesGatewayStatusCallback() + throws Exception { + final IkeInternalException exception = new IkeInternalException(mock(IOException.class)); + getChildSessionCallback().onClosedExceptionally(exception); + mTestLooper.dispatchAll(); + + verify(mGatewayStatusCallback) + .onGatewayConnectionError( + eq(mConfig.getRequiredUnderlyingCapabilities()), + eq(VCN_ERROR_CODE_INTERNAL_ERROR), + any(), + any()); } @Test @@ -223,5 +252,42 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection // Since network never validated, verify mSafeModeTimeoutAlarm not canceled verifyNoMoreInteractions(mSafeModeTimeoutAlarm); + + // IkeSession closed with no error, so verify that the GatewayStatusCallback was not + // notified + verifyNoMoreInteractions(mGatewayStatusCallback); + } + + private void verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( + IkeException cause, @VcnErrorCode int expectedErrorType) { + getIkeSessionCallback().onClosedExceptionally(cause); + mTestLooper.dispatchAll(); + + verify(mIkeSession).close(); + + verify(mGatewayStatusCallback) + .onGatewayConnectionError( + eq(mConfig.getRequiredUnderlyingCapabilities()), + eq(expectedErrorType), + any(), + any()); + } + + @Test + public void testIkeSessionClosedExceptionallyAuthenticationFailure() throws Exception { + verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( + new AuthenticationFailedException("vcn test"), VCN_ERROR_CODE_CONFIG_ERROR); + } + + @Test + public void testIkeSessionClosedExceptionallyDnsFailure() throws Exception { + verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( + new IkeInternalException(new UnknownHostException()), VCN_ERROR_CODE_NETWORK_ERROR); + } + + @Test + public void testIkeSessionClosedExceptionallyInternalFailure() throws Exception { + verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( + new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 8e142c095a..9d33682712 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -34,7 +34,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; -import com.android.server.VcnManagementService.VcnSafeModeCallback; +import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; @@ -56,7 +56,7 @@ public class VcnTest { private VcnContext mVcnContext; private TelephonySubscriptionSnapshot mSubscriptionSnapshot; private VcnNetworkProvider mVcnNetworkProvider; - private VcnSafeModeCallback mVcnSafeModeCallback; + private VcnCallback mVcnCallback; private Vcn.Dependencies mDeps; private ArgumentCaptor mGatewayStatusCallbackCaptor; @@ -72,7 +72,7 @@ public class VcnTest { mVcnContext = mock(VcnContext.class); mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); mVcnNetworkProvider = mock(VcnNetworkProvider.class); - mVcnSafeModeCallback = mock(VcnSafeModeCallback.class); + mVcnCallback = mock(VcnCallback.class); mDeps = mock(Vcn.Dependencies.class); mTestLooper = new TestLooper(); @@ -104,7 +104,7 @@ public class VcnTest { TEST_SUB_GROUP, mConfig, mSubscriptionSnapshot, - mVcnSafeModeCallback, + mVcnCallback, mDeps); } @@ -179,6 +179,6 @@ public class VcnTest { verify(gatewayConnection).teardownAsynchronously(); } verify(mVcnNetworkProvider).unregisterListener(requestListener); - verify(mVcnSafeModeCallback).onEnteredSafeMode(); + verify(mVcnCallback).onEnteredSafeMode(); } } From 6753e2bb540f85cc8a81479799e858732fe8f80a Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 16 Feb 2021 09:42:16 -0800 Subject: [PATCH 0077/1057] Correct comment for safe mode alarm in VcnGatewayConnection. Bug: 178140973 Test: atest FrameworksVcnTests Change-Id: I0cadd145fe41f5589fb79725a4370aed527927a0 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8f2f56aa07..733d8cb558 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1635,8 +1635,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void exitState() { - // Attempt to set the safe mode alarm - this requires the Vcn Network being validated - // while in ConnectedState (which cancels the previous alarm) + // Will only set a new alarm if no safe mode alarm is currently scheduled. setSafeModeAlarm(); } } From 91418a61fcc46ea0ea084528afa8688488947259 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 19:42:55 -0800 Subject: [PATCH 0078/1057] [LSC] Add LOCAL_LICENSE_KINDS to cts Added SPDX-license-identifier-Apache-2.0 to: apps/CrossProfileTestApp/Android.bp apps/CtsVerifier/jni/audio_loopback/Android.bp apps/CtsVerifier/jni/midi/Android.bp apps/CtsVerifier/jni/verifier/Android.bp apps/CtsVerifierInstantApp/Android.bp apps/CtsVerifierUSBCompanion/Android.bp apps/EmptyDeviceAdmin/Android.bp apps/EmptyDeviceOwner/Android.bp apps/ForceStopHelperApp/Android.bp apps/NotificationBot/Android.bp apps/OomCatcher/Android.bp apps/PermissionApp/Android.bp apps/VpnApp/Android.bp common/device-side/device-info/Android.bp common/device-side/device-info/tests/Android.bp common/device-side/nativetesthelper/Android.bp common/device-side/nativetesthelper/jni/Android.bp common/device-side/preconditions/Android.bp common/device-side/test-app/Android.bp common/device-side/util-axt/Android.bp common/device-side/util-axt/tests/Android.bp common/device-side/util/jni/Android.bp common/host-side/util-axt/Android.bp helpers/default/Android.bp hostsidetests/abioverride/Android.bp hostsidetests/abioverride/app/Android.bp hostsidetests/abioverride/app/jni/Android.bp hostsidetests/accounts/Android.bp hostsidetests/accounts/test-apps/AccountManagerCrossUserApp/Android.bp hostsidetests/adb/Android.mk hostsidetests/adbmanager/Android.bp hostsidetests/angle/Android.bp hostsidetests/angle/app/common/Android.bp hostsidetests/angle/app/driverTest/Android.bp hostsidetests/angle/app/driverTestSecondary/Android.bp hostsidetests/apex/Android.bp hostsidetests/appbinding/app/Android.bp hostsidetests/appbinding/hostside/Android.bp hostsidetests/appcompat/compatchanges/Android.bp hostsidetests/appcompat/compatchanges/app/Android.bp hostsidetests/appcompat/compatchanges/preInstallOverrideApps/Android.bp hostsidetests/appcompat/host/lib/Android.bp hostsidetests/appcompat/strictjavapackages/Android.bp hostsidetests/appsecurity/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppAccessData/Android.bp hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppWithData/Android.bp hostsidetests/appsecurity/test-apps/ApplicationVisibilityCrossUserApp/Android.bp hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/compressed_arsc/Android.bp hostsidetests/appsecurity/test-apps/DeviceIdentifiers/Android.bp hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/EncryptionApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.bp hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.bp hostsidetests/appsecurity/test-apps/InstantUpgradeApp/Android.bp hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.bp hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk hostsidetests/appsecurity/test-apps/ListeningPortsApp/Android.bp hostsidetests/appsecurity/test-apps/LocationPolicyApp/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000000000ffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version00000000ffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ff00000000/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ffffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/src-common/Android.bp hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.bp hostsidetests/appsecurity/test-apps/OrderedActivityApp/Android.bp hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk hostsidetests/appsecurity/test-apps/StorageApp/Android.bp hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.bp hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.bp hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailActivity/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailApplication/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailProvider/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailReceiver/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailService/Android.bp hostsidetests/appsecurity/test-apps/UseProcessSuccess/Android.bp hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.bp hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permUse/Android.bp hostsidetests/appsecurity/test-apps/keysets/testApp/Android.bp hostsidetests/appsecurity/test-apps/keysets/uA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.bp hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uNone/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAll/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAndroid/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayApp/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyProduct/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySignatureDifferent/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySystem/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyVendor/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayTarget/Android.bp hostsidetests/appsecurity/test-apps/stubime/Android.bp hostsidetests/atrace/Android.bp hostsidetests/atrace/AtraceTestApp/Android.bp hostsidetests/atrace/AtraceTestApp/jni/Android.bp hostsidetests/backup/AllowBackup/Android.bp hostsidetests/backup/AllowBackup/BackupAllowedApp/Android.bp hostsidetests/backup/AllowBackup/BackupNotAllowedApp/Android.bp hostsidetests/backup/Android.bp hostsidetests/backup/AutoRestoreApp/Android.bp hostsidetests/backup/BackupTransportApp/Android.bp hostsidetests/backup/FullBackupOnly/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.bp hostsidetests/backup/KeyValueApp/Android.bp hostsidetests/backup/OtherSoundsSettingsApp/Android.bp hostsidetests/backup/PreservedSettingsApp/Android.bp hostsidetests/backup/ProfileFullBackupApp/Android.bp hostsidetests/backup/ProfileKeyValueApp/Android.bp hostsidetests/backup/ProfileSerialNumberApp/Android.bp hostsidetests/backup/RestoreAnyVersion/Android.bp hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreSessionTest/Android.bp hostsidetests/backup/SharedPreferencesRestoreApp/Android.bp hostsidetests/backup/SuccessNotificationApp/Android.bp hostsidetests/backup/SyncAdapterSettingsApp/Android.bp hostsidetests/backup/fullbackupapp/Android.bp hostsidetests/backup/includeexcludeapp/Android.bp hostsidetests/backup/restoresessionapp1/Android.bp hostsidetests/backup/restoresessionapp2/Android.bp hostsidetests/backup/restoresessionapp3/Android.bp hostsidetests/blobstore/Android.bp hostsidetests/bootstats/Android.bp hostsidetests/car/Android.bp hostsidetests/classloaders/splits/Android.bp hostsidetests/classloaders/splits/apps/Android.bp hostsidetests/classloaders/splits/apps/feature_a/Android.bp hostsidetests/classloaders/splits/apps/feature_b/Android.bp hostsidetests/classloaders/useslibrary/Android.bp hostsidetests/classloaders/useslibrary/app/Android.bp hostsidetests/compilation/Android.bp hostsidetests/compilation/app/Android.bp hostsidetests/content/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileApp/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileTestServiceApp/Android.bp hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp hostsidetests/cpptools/Android.bp hostsidetests/cpptools/test-apps/BasicApp/Android.bp hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp hostsidetests/deviceidle/Android.bp hostsidetests/devicepolicy/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp hostsidetests/devicepolicy/app/AccountManagement/Android.bp hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp hostsidetests/devicepolicy/app/Assistant/Android.bp hostsidetests/devicepolicy/app/AutofillApp/Android.bp hostsidetests/devicepolicy/app/CertInstaller/Android.bp hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp hostsidetests/devicepolicy/app/CustomizationApp/Android.bp hostsidetests/devicepolicy/app/DelegateApp/Android.bp hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp hostsidetests/devicepolicy/app/DeviceOwner/Android.bp hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp hostsidetests/devicepolicy/app/IntentReceiver/Android.bp hostsidetests/devicepolicy/app/IntentSender/Android.bp hostsidetests/devicepolicy/app/LauncherTests/Android.bp hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp hostsidetests/devicepolicy/app/ManagedProfile/Android.bp hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp hostsidetests/devicepolicy/app/NotificationSender/Android.bp hostsidetests/devicepolicy/app/PackageInstaller/Android.bp hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp hostsidetests/devicepolicy/app/PrintingApp/Android.bp hostsidetests/devicepolicy/app/ProfileOwner/Android.bp hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp hostsidetests/devicepolicy/app/SharingApps/Android.bp hostsidetests/devicepolicy/app/SimpleApp/Android.bp hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp hostsidetests/devicepolicy/app/SuspensionChecker/Android.bp hostsidetests/devicepolicy/app/TestApps/Android.bp hostsidetests/devicepolicy/app/TestIme/Android.bp hostsidetests/devicepolicy/app/TestLauncher/Android.bp hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp hostsidetests/devicepolicy/app/WidgetProvider/Android.bp hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp hostsidetests/dexmetadata/app/Android.bp hostsidetests/dexmetadata/app/SplitApp/Android.bp hostsidetests/dexmetadata/app/SplitApp/SplitAppFeatureA/Android.bp hostsidetests/dexmetadata/host/Android.bp hostsidetests/dumpsys/Android.bp hostsidetests/dumpsys/apps/FramestatsTestApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.bp hostsidetests/dumpsys/apps/storagedapp/Android.bp hostsidetests/edi/Android.bp hostsidetests/gputools/apps/Android.bp hostsidetests/graphics/gpuprofiling/Android.bp hostsidetests/graphics/gpuprofiling/app/Android.bp hostsidetests/harmfulappwarning/Android.bp hostsidetests/harmfulappwarning/sampleapp/Android.bp hostsidetests/harmfulappwarning/testapp/Android.bp hostsidetests/hdmicec/Android.bp hostsidetests/hdmicec/app/Android.bp hostsidetests/incident/Android.bp hostsidetests/incident/apps/batterystatsapp/Android.bp hostsidetests/incident/apps/boundwidgetapp/Android.bp hostsidetests/incident/apps/errorsapp/Android.bp hostsidetests/incident/apps/errorsapp/jni/Android.bp hostsidetests/incident/apps/graphicsstatsapp/Android.bp hostsidetests/incident/apps/notificationsapp/Android.bp hostsidetests/incident/apps/procstatsapp/Android.bp hostsidetests/incrementalinstall/Android.bp hostsidetests/incrementalinstall/app/Android.bp hostsidetests/incrementalinstall/app/dynamicasset/Android.bp hostsidetests/incrementalinstall/app/dynamiccode/Android.bp hostsidetests/incrementalinstall/app/nativelibcompressed/Android.bp hostsidetests/incrementalinstall/app/nativelibuncompressed/Android.bp hostsidetests/incrementalinstall/appvalidator/Android.bp hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/jni/Android.bp hostsidetests/incrementalinstall/common/Android.bp hostsidetests/inputmethodservice/common/Android.bp hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp hostsidetests/inputmethodservice/deviceside/ime1/Android.bp hostsidetests/inputmethodservice/deviceside/ime2/Android.bp hostsidetests/inputmethodservice/deviceside/lib/Android.bp hostsidetests/inputmethodservice/deviceside/provider/Android.bp hostsidetests/inputmethodservice/hostside/Android.bp hostsidetests/jdwpsecurity/Android.bp hostsidetests/jdwpsecurity/app/Android.bp hostsidetests/jdwptunnel/Android.bp hostsidetests/jdwptunnel/sampleapps/ddmsapp/Android.bp hostsidetests/jdwptunnel/sampleapps/debuggableapp/Android.bp hostsidetests/jdwptunnel/sampleapps/profileableapp/Android.bp hostsidetests/jvmti/allocation-tracking/Android.bp hostsidetests/jvmti/allocation-tracking/app/Android.bp hostsidetests/jvmti/attaching/Android.bp hostsidetests/jvmti/base/app/Android.bp hostsidetests/jvmti/base/host/Android.bp hostsidetests/jvmti/base/jni/Android.bp hostsidetests/jvmti/base/run-test-based-app/Android.bp hostsidetests/jvmti/redefining/Android.bp hostsidetests/jvmti/redefining/app/Android.bp hostsidetests/jvmti/run-tests/Android.bp hostsidetests/jvmti/run-tests/test-1900/Android.bp hostsidetests/jvmti/run-tests/test-1900/app/Android.bp hostsidetests/jvmti/run-tests/test-1901/Android.bp hostsidetests/jvmti/run-tests/test-1901/app/Android.bp hostsidetests/jvmti/run-tests/test-1902/Android.bp hostsidetests/jvmti/run-tests/test-1902/app/Android.bp hostsidetests/jvmti/run-tests/test-1903/Android.bp hostsidetests/jvmti/run-tests/test-1903/app/Android.bp hostsidetests/jvmti/run-tests/test-1904/Android.bp hostsidetests/jvmti/run-tests/test-1904/app/Android.bp hostsidetests/jvmti/run-tests/test-1906/Android.bp hostsidetests/jvmti/run-tests/test-1906/app/Android.bp hostsidetests/jvmti/run-tests/test-1907/Android.bp hostsidetests/jvmti/run-tests/test-1907/app/Android.bp hostsidetests/jvmti/run-tests/test-1908/Android.bp hostsidetests/jvmti/run-tests/test-1908/app/Android.bp hostsidetests/jvmti/run-tests/test-1909/Android.bp hostsidetests/jvmti/run-tests/test-1909/app/Android.bp hostsidetests/jvmti/run-tests/test-1910/Android.bp hostsidetests/jvmti/run-tests/test-1910/app/Android.bp hostsidetests/jvmti/run-tests/test-1911/Android.bp hostsidetests/jvmti/run-tests/test-1911/app/Android.bp hostsidetests/jvmti/run-tests/test-1912/Android.bp hostsidetests/jvmti/run-tests/test-1912/app/Android.bp hostsidetests/jvmti/run-tests/test-1913/Android.bp hostsidetests/jvmti/run-tests/test-1913/app/Android.bp hostsidetests/jvmti/run-tests/test-1914/Android.bp hostsidetests/jvmti/run-tests/test-1914/app/Android.bp hostsidetests/jvmti/run-tests/test-1915/Android.bp hostsidetests/jvmti/run-tests/test-1915/app/Android.bp hostsidetests/jvmti/run-tests/test-1916/Android.bp hostsidetests/jvmti/run-tests/test-1916/app/Android.bp hostsidetests/jvmti/run-tests/test-1917/Android.bp hostsidetests/jvmti/run-tests/test-1917/app/Android.bp hostsidetests/jvmti/run-tests/test-1920/Android.bp hostsidetests/jvmti/run-tests/test-1920/app/Android.bp hostsidetests/jvmti/run-tests/test-1921/Android.bp hostsidetests/jvmti/run-tests/test-1921/app/Android.bp hostsidetests/jvmti/run-tests/test-1922/Android.bp hostsidetests/jvmti/run-tests/test-1922/app/Android.bp hostsidetests/jvmti/run-tests/test-1923/Android.bp hostsidetests/jvmti/run-tests/test-1923/app/Android.bp hostsidetests/jvmti/run-tests/test-1924/Android.bp hostsidetests/jvmti/run-tests/test-1924/app/Android.bp hostsidetests/jvmti/run-tests/test-1925/Android.bp hostsidetests/jvmti/run-tests/test-1925/app/Android.bp hostsidetests/jvmti/run-tests/test-1926/Android.bp hostsidetests/jvmti/run-tests/test-1926/app/Android.bp hostsidetests/jvmti/run-tests/test-1927/Android.bp hostsidetests/jvmti/run-tests/test-1927/app/Android.bp hostsidetests/jvmti/run-tests/test-1928/Android.bp hostsidetests/jvmti/run-tests/test-1928/app/Android.bp hostsidetests/jvmti/run-tests/test-1930/Android.bp hostsidetests/jvmti/run-tests/test-1930/app/Android.bp hostsidetests/jvmti/run-tests/test-1931/Android.bp hostsidetests/jvmti/run-tests/test-1931/app/Android.bp hostsidetests/jvmti/run-tests/test-1932/Android.bp hostsidetests/jvmti/run-tests/test-1932/app/Android.bp hostsidetests/jvmti/run-tests/test-1933/Android.bp hostsidetests/jvmti/run-tests/test-1933/app/Android.bp hostsidetests/jvmti/run-tests/test-1934/Android.bp hostsidetests/jvmti/run-tests/test-1934/app/Android.bp hostsidetests/jvmti/run-tests/test-1936/Android.bp hostsidetests/jvmti/run-tests/test-1936/app/Android.bp hostsidetests/jvmti/run-tests/test-1937/Android.bp hostsidetests/jvmti/run-tests/test-1937/app/Android.bp hostsidetests/jvmti/run-tests/test-1939/Android.bp hostsidetests/jvmti/run-tests/test-1939/app/Android.bp hostsidetests/jvmti/run-tests/test-1941/Android.bp hostsidetests/jvmti/run-tests/test-1941/app/Android.bp hostsidetests/jvmti/run-tests/test-1942/Android.bp hostsidetests/jvmti/run-tests/test-1942/app/Android.bp hostsidetests/jvmti/run-tests/test-1943/Android.bp hostsidetests/jvmti/run-tests/test-1943/app/Android.bp hostsidetests/jvmti/run-tests/test-1953/Android.bp hostsidetests/jvmti/run-tests/test-1953/app/Android.bp hostsidetests/jvmti/run-tests/test-1958/Android.bp hostsidetests/jvmti/run-tests/test-1958/app/Android.bp hostsidetests/jvmti/run-tests/test-1962/Android.bp hostsidetests/jvmti/run-tests/test-1962/app/Android.bp hostsidetests/jvmti/run-tests/test-1967/Android.bp hostsidetests/jvmti/run-tests/test-1967/app/Android.bp hostsidetests/jvmti/run-tests/test-1968/Android.bp hostsidetests/jvmti/run-tests/test-1968/app/Android.bp hostsidetests/jvmti/run-tests/test-1969/Android.bp hostsidetests/jvmti/run-tests/test-1969/app/Android.bp hostsidetests/jvmti/run-tests/test-1970/Android.bp hostsidetests/jvmti/run-tests/test-1970/app/Android.bp hostsidetests/jvmti/run-tests/test-1971/Android.bp hostsidetests/jvmti/run-tests/test-1971/app/Android.bp hostsidetests/jvmti/run-tests/test-1974/Android.bp hostsidetests/jvmti/run-tests/test-1974/app/Android.bp hostsidetests/jvmti/run-tests/test-1975/Android.bp hostsidetests/jvmti/run-tests/test-1975/app/Android.bp hostsidetests/jvmti/run-tests/test-1976/Android.bp hostsidetests/jvmti/run-tests/test-1976/app/Android.bp hostsidetests/jvmti/run-tests/test-1977/Android.bp hostsidetests/jvmti/run-tests/test-1977/app/Android.bp hostsidetests/jvmti/run-tests/test-1978/Android.bp hostsidetests/jvmti/run-tests/test-1978/app/Android.bp hostsidetests/jvmti/run-tests/test-1979/Android.bp hostsidetests/jvmti/run-tests/test-1979/app/Android.bp hostsidetests/jvmti/run-tests/test-1981/Android.bp hostsidetests/jvmti/run-tests/test-1981/app/Android.bp hostsidetests/jvmti/run-tests/test-1982/Android.bp hostsidetests/jvmti/run-tests/test-1982/app/Android.bp hostsidetests/jvmti/run-tests/test-1983/Android.bp hostsidetests/jvmti/run-tests/test-1983/app/Android.bp hostsidetests/jvmti/run-tests/test-1984/Android.bp hostsidetests/jvmti/run-tests/test-1984/app/Android.bp hostsidetests/jvmti/run-tests/test-1988/Android.bp hostsidetests/jvmti/run-tests/test-1988/app/Android.bp hostsidetests/jvmti/run-tests/test-1989/Android.bp hostsidetests/jvmti/run-tests/test-1989/app/Android.bp hostsidetests/jvmti/run-tests/test-1990/Android.bp hostsidetests/jvmti/run-tests/test-1990/app/Android.bp hostsidetests/jvmti/run-tests/test-1991/Android.bp hostsidetests/jvmti/run-tests/test-1991/app/Android.bp hostsidetests/jvmti/run-tests/test-1992/Android.bp hostsidetests/jvmti/run-tests/test-1992/app/Android.bp hostsidetests/jvmti/run-tests/test-1994/Android.bp hostsidetests/jvmti/run-tests/test-1994/app/Android.bp hostsidetests/jvmti/run-tests/test-1995/Android.bp hostsidetests/jvmti/run-tests/test-1995/app/Android.bp hostsidetests/jvmti/run-tests/test-1996/Android.bp hostsidetests/jvmti/run-tests/test-1996/app/Android.bp hostsidetests/jvmti/run-tests/test-1997/Android.bp hostsidetests/jvmti/run-tests/test-1997/app/Android.bp hostsidetests/jvmti/run-tests/test-1998/Android.bp hostsidetests/jvmti/run-tests/test-1998/app/Android.bp hostsidetests/jvmti/run-tests/test-1999/Android.bp hostsidetests/jvmti/run-tests/test-1999/app/Android.bp hostsidetests/jvmti/run-tests/test-2001/Android.bp hostsidetests/jvmti/run-tests/test-2001/app/Android.bp hostsidetests/jvmti/run-tests/test-2002/Android.bp hostsidetests/jvmti/run-tests/test-2002/app/Android.bp hostsidetests/jvmti/run-tests/test-2003/Android.bp hostsidetests/jvmti/run-tests/test-2003/app/Android.bp hostsidetests/jvmti/run-tests/test-2004/Android.bp hostsidetests/jvmti/run-tests/test-2004/app/Android.bp hostsidetests/jvmti/run-tests/test-2005/Android.bp hostsidetests/jvmti/run-tests/test-2005/app/Android.bp hostsidetests/jvmti/run-tests/test-2006/Android.bp hostsidetests/jvmti/run-tests/test-2006/app/Android.bp hostsidetests/jvmti/run-tests/test-2007/Android.bp hostsidetests/jvmti/run-tests/test-2007/app/Android.bp hostsidetests/jvmti/run-tests/test-902/Android.bp hostsidetests/jvmti/run-tests/test-902/app/Android.bp hostsidetests/jvmti/run-tests/test-903/Android.bp hostsidetests/jvmti/run-tests/test-903/app/Android.bp hostsidetests/jvmti/run-tests/test-904/Android.bp hostsidetests/jvmti/run-tests/test-904/app/Android.bp hostsidetests/jvmti/run-tests/test-905/Android.bp hostsidetests/jvmti/run-tests/test-905/app/Android.bp hostsidetests/jvmti/run-tests/test-906/Android.bp hostsidetests/jvmti/run-tests/test-906/app/Android.bp hostsidetests/jvmti/run-tests/test-907/Android.bp hostsidetests/jvmti/run-tests/test-907/app/Android.bp hostsidetests/jvmti/run-tests/test-908/Android.bp hostsidetests/jvmti/run-tests/test-908/app/Android.bp hostsidetests/jvmti/run-tests/test-910/Android.bp hostsidetests/jvmti/run-tests/test-910/app/Android.bp hostsidetests/jvmti/run-tests/test-911/Android.bp hostsidetests/jvmti/run-tests/test-911/app/Android.bp hostsidetests/jvmti/run-tests/test-912/Android.bp hostsidetests/jvmti/run-tests/test-912/app/Android.bp hostsidetests/jvmti/run-tests/test-913/Android.bp hostsidetests/jvmti/run-tests/test-913/app/Android.bp hostsidetests/jvmti/run-tests/test-914/Android.bp hostsidetests/jvmti/run-tests/test-914/app/Android.bp hostsidetests/jvmti/run-tests/test-915/Android.bp hostsidetests/jvmti/run-tests/test-915/app/Android.bp hostsidetests/jvmti/run-tests/test-917/Android.bp hostsidetests/jvmti/run-tests/test-917/app/Android.bp hostsidetests/jvmti/run-tests/test-918/Android.bp hostsidetests/jvmti/run-tests/test-918/app/Android.bp hostsidetests/jvmti/run-tests/test-919/Android.bp hostsidetests/jvmti/run-tests/test-919/app/Android.bp hostsidetests/jvmti/run-tests/test-920/Android.bp hostsidetests/jvmti/run-tests/test-920/app/Android.bp hostsidetests/jvmti/run-tests/test-922/Android.bp hostsidetests/jvmti/run-tests/test-922/app/Android.bp hostsidetests/jvmti/run-tests/test-923/Android.bp hostsidetests/jvmti/run-tests/test-923/app/Android.bp hostsidetests/jvmti/run-tests/test-924/Android.bp hostsidetests/jvmti/run-tests/test-924/app/Android.bp hostsidetests/jvmti/run-tests/test-926/Android.bp hostsidetests/jvmti/run-tests/test-926/app/Android.bp hostsidetests/jvmti/run-tests/test-927/Android.bp hostsidetests/jvmti/run-tests/test-927/app/Android.bp hostsidetests/jvmti/run-tests/test-928/Android.bp hostsidetests/jvmti/run-tests/test-928/app/Android.bp hostsidetests/jvmti/run-tests/test-930/Android.bp hostsidetests/jvmti/run-tests/test-930/app/Android.bp hostsidetests/jvmti/run-tests/test-931/Android.bp hostsidetests/jvmti/run-tests/test-931/app/Android.bp hostsidetests/jvmti/run-tests/test-932/Android.bp hostsidetests/jvmti/run-tests/test-932/app/Android.bp hostsidetests/jvmti/run-tests/test-940/Android.bp hostsidetests/jvmti/run-tests/test-940/app/Android.bp hostsidetests/jvmti/run-tests/test-942/Android.bp hostsidetests/jvmti/run-tests/test-942/app/Android.bp hostsidetests/jvmti/run-tests/test-944/Android.bp hostsidetests/jvmti/run-tests/test-944/app/Android.bp hostsidetests/jvmti/run-tests/test-945/Android.bp hostsidetests/jvmti/run-tests/test-945/app/Android.bp hostsidetests/jvmti/run-tests/test-947/Android.bp hostsidetests/jvmti/run-tests/test-947/app/Android.bp hostsidetests/jvmti/run-tests/test-951/Android.bp hostsidetests/jvmti/run-tests/test-951/app/Android.bp hostsidetests/jvmti/run-tests/test-982/Android.bp hostsidetests/jvmti/run-tests/test-982/app/Android.bp hostsidetests/jvmti/run-tests/test-983/Android.bp hostsidetests/jvmti/run-tests/test-983/app/Android.bp hostsidetests/jvmti/run-tests/test-984/Android.bp hostsidetests/jvmti/run-tests/test-984/app/Android.bp hostsidetests/jvmti/run-tests/test-985/Android.bp hostsidetests/jvmti/run-tests/test-985/app/Android.bp hostsidetests/jvmti/run-tests/test-986/Android.bp hostsidetests/jvmti/run-tests/test-986/app/Android.bp hostsidetests/jvmti/run-tests/test-988/Android.bp hostsidetests/jvmti/run-tests/test-988/app/Android.bp hostsidetests/jvmti/run-tests/test-989/Android.bp hostsidetests/jvmti/run-tests/test-989/app/Android.bp hostsidetests/jvmti/run-tests/test-990/Android.bp hostsidetests/jvmti/run-tests/test-990/app/Android.bp hostsidetests/jvmti/run-tests/test-991/Android.bp hostsidetests/jvmti/run-tests/test-991/app/Android.bp hostsidetests/jvmti/run-tests/test-992/Android.bp hostsidetests/jvmti/run-tests/test-992/app/Android.bp hostsidetests/jvmti/run-tests/test-993/Android.bp hostsidetests/jvmti/run-tests/test-993/app/Android.bp hostsidetests/jvmti/run-tests/test-994/Android.bp hostsidetests/jvmti/run-tests/test-994/app/Android.bp hostsidetests/jvmti/run-tests/test-995/Android.bp hostsidetests/jvmti/run-tests/test-995/app/Android.bp hostsidetests/jvmti/run-tests/test-996/Android.bp hostsidetests/jvmti/run-tests/test-996/app/Android.bp hostsidetests/jvmti/run-tests/test-997/Android.bp hostsidetests/jvmti/run-tests/test-997/app/Android.bp hostsidetests/jvmti/tagging/Android.bp hostsidetests/jvmti/tagging/app/Android.bp hostsidetests/media/Android.bp hostsidetests/media/app/MediaSessionTest/Android.bp hostsidetests/media/app/MediaSessionTestHelper/Android.bp hostsidetests/media/bitstreams/Android.bp hostsidetests/media/bitstreams/app/Android.bp hostsidetests/media/bitstreams/common/Android.bp hostsidetests/monkey/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.bp hostsidetests/multiuser/Android.bp hostsidetests/numberblocking/Android.bp hostsidetests/numberblocking/app/Android.bp hostsidetests/os/Android.bp hostsidetests/os/app/Android.bp hostsidetests/os/test-apps/EnvironmentTestApp/Android.bp hostsidetests/os/test-apps/HostLinkVerificationApp/Android.bp hostsidetests/os/test-apps/InattentiveSleepTestApp/Android.bp hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp hostsidetests/os/test-apps/ProcfsTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.bp hostsidetests/packagemanager/codepath/Android.bp hostsidetests/packagemanager/codepath/app/Android.bp hostsidetests/packagemanager/dynamicmime/Android.bp hostsidetests/packagemanager/dynamicmime/app/Android.bp hostsidetests/packagemanager/dynamicmime/common/Android.bp hostsidetests/packagemanager/dynamicmime/test/Android.bp hostsidetests/packagemanager/extractnativelibs/Android.bp hostsidetests/packagemanager/extractnativelibs/apps/Android.bp hostsidetests/rollback/Android.bp hostsidetests/sample/Android.bp hostsidetests/sample/app/Android.bp hostsidetests/sample/app2/Android.bp hostsidetests/scopedstorage/Android.bp hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp hostsidetests/seccomp/Android.bp hostsidetests/seccomp/app/Android.bp hostsidetests/seccomp/app/jni/Android.bp hostsidetests/security/Android.mk hostsidetests/securitybulletin/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-137878930/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-4658/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5131/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0814/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0840/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13241/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13253/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9472/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9491/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9347/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0069/Android.bp hostsidetests/securitybulletin/securityPatch/includes/Android.bp hostsidetests/securitybulletin/securityPatch/pac/Android.bp hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp hostsidetests/settings/Android.bp hostsidetests/settings/app/DeviceOwnerApp/Android.bp hostsidetests/shortcuts/deviceside/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher1/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher2/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher3/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher1/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher2/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher3/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nobackup/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_wrongkey/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/common/Android.bp hostsidetests/shortcuts/deviceside/multiuser/Android.bp hostsidetests/shortcuts/deviceside/upgrade/Android.bp hostsidetests/shortcuts/hostside/Android.bp hostsidetests/signedconfig/app/Android.bp hostsidetests/signedconfig/hostside/Android.bp hostsidetests/stagedinstall/Android.bp hostsidetests/sustainedperf/shadertoy_android/jni/Android.bp hostsidetests/systemui/Android.bp hostsidetests/systemui/app/Android.bp hostsidetests/systemui/audiorecorder_app_audiorecord/Android.bp hostsidetests/systemui/audiorecorder_app_mediarecorder/Android.bp hostsidetests/systemui/audiorecorder_base/Android.bp hostsidetests/tagging/Android.bp hostsidetests/tagging/common/Android.bp hostsidetests/tagging/manifest_disabled/Android.bp hostsidetests/tagging/manifest_enabled_sdk_29/Android.bp hostsidetests/tagging/manifest_enabled_sdk_30/Android.bp hostsidetests/tagging/sdk_29/Android.bp hostsidetests/tagging/sdk_30/Android.bp hostsidetests/telephony/Android.bp hostsidetests/telephony/devicetest/Android.bp hostsidetests/telephonyprovider/Android.bp hostsidetests/telephonyprovider/devicetest/Android.bp hostsidetests/testharness/Android.bp hostsidetests/testharness/app/Android.bp hostsidetests/theme/Android.mk hostsidetests/theme/app/Android.bp hostsidetests/trustedvoice/Android.bp hostsidetests/trustedvoice/app/Android.bp hostsidetests/tv/Android.bp hostsidetests/tv/app/Android.bp hostsidetests/tv/app2/Android.bp hostsidetests/tzdata/Android.bp hostsidetests/ui/Android.mk hostsidetests/ui/appA/Android.bp hostsidetests/ui/appB/Android.bp hostsidetests/ui/control/Android.bp hostsidetests/usage/Android.bp hostsidetests/usage/app/Android.bp hostsidetests/usb/Android.bp hostsidetests/usb/SerialTestApp/Android.bp hostsidetests/userspacereboot/Android.bp hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp hostsidetests/utils/Android.bp hostsidetests/webkit/Android.bp hostsidetests/webkit/app/Android.bp hostsidetests/wifibroadcasts/Android.bp hostsidetests/wifibroadcasts/app/Android.bp libs/deviceutillegacy/Android.bp libs/helpers/core/Android.bp libs/helpers/core/tests/Android.bp libs/helpers/interfaces/Android.bp libs/input/Android.bp libs/install/Android.bp libs/json/Android.bp libs/midi/Android.bp libs/rollback/Android.bp libs/shim/Android.bp libs/view/Android.bp libs/vogar-expect/Android.bp suite/audio_quality/executable/Android.bp suite/audio_quality/lib/Android.bp suite/audio_quality/test/Android.bp tests/AlarmManager/Android.bp tests/AlarmManager/app/Android.bp tests/BlobStore/Android.bp tests/DropBoxManager/Android.bp tests/JobScheduler/Android.bp tests/JobScheduler/JobTestApp/Android.bp tests/JobSchedulerSharedUid/Android.bp tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp tests/JobSchedulerSharedUid/jobperm/Android.bp tests/JobSchedulerSharedUid/shareduid/Android.bp tests/ProcessTest/Android.bp tests/ProcessTest/NoShareUidApp/Android.bp tests/ProcessTest/ShareUidApp/Android.bp tests/acceleration/Android.bp tests/accessibility/Android.bp tests/accessibilityservice/Android.bp tests/accessibilityservice/test-apps/WidgetProvider/Android.bp tests/accessibilityservice/testsdk29/Android.bp tests/admin/Android.bp tests/admin/app/Android.bp tests/app/ActivityManagerApi29Test/Android.bp tests/app/Android.bp tests/app/BadProviderStubs/Android.bp tests/app/CantSaveState1/Android.bp tests/app/CantSaveState2/Android.bp tests/app/NotificationDelegator/Android.bp tests/app/NotificationListener/Android.bp tests/app/NotificationProvider/Android.bp tests/app/StorageDelegator/Android.bp tests/app/app/Android.bp tests/appintegrity/Android.bp tests/apppredictionservice/Android.bp tests/aslr/Android.bp tests/attentionservice/Android.bp tests/autofillservice/Android.bp tests/backup/Android.bp tests/backup/app/Android.bp tests/bugreport/Android.bp tests/camera/Android.bp tests/camera/libctscamera2jni/Android.mk tests/camera/utils/Android.bp tests/contentcaptureservice/Android.bp tests/contentcaptureservice/OutsideOfPackageActivity/Android.bp tests/contentsuggestions/Android.bp tests/controls/Android.bp tests/core/runner-axt/Android.bp tests/filesystem/Android.bp tests/fragment/Android.bp tests/fragment/sdk26/Android.bp tests/framework/base/windowmanager/Android.bp tests/framework/base/windowmanager/alertwindowapp/Android.bp tests/framework/base/windowmanager/alertwindowappsdk25/Android.bp tests/framework/base/windowmanager/alertwindowservice/Android.bp tests/framework/base/windowmanager/app/Android.bp tests/framework/base/windowmanager/app27/Android.bp tests/framework/base/windowmanager/appAShareUid/Android.bp tests/framework/base/windowmanager/appBShareUid/Android.bp tests/framework/base/windowmanager/appDeprecatedSdk/Android.bp tests/framework/base/windowmanager/appDisplaySize/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp tests/framework/base/windowmanager/appProfileable/Android.bp tests/framework/base/windowmanager/appSecondUid/Android.bp tests/framework/base/windowmanager/appThirdUid/Android.bp tests/framework/base/windowmanager/app_base/Android.bp tests/framework/base/windowmanager/backgroundactivity/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppA/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppB/Android.bp tests/framework/base/windowmanager/backgroundactivity/common/Android.bp tests/framework/base/windowmanager/dndsourceapp/Android.bp tests/framework/base/windowmanager/dndtargetapp/Android.bp tests/framework/base/windowmanager/dndtargetappsdk23/Android.bp tests/framework/base/windowmanager/jetpack/Android.bp tests/framework/base/windowmanager/testsdk25/Android.bp tests/framework/base/windowmanager/testsdk28/Android.bp tests/framework/base/windowmanager/testsdk29/Android.bp tests/framework/base/windowmanager/translucentapp/Android.bp tests/framework/base/windowmanager/translucentappsdk26/Android.bp tests/framework/base/windowmanager/util/Android.bp tests/inputmethod/Android.bp tests/inputmethod/mockime/Android.bp tests/inputmethod/testapp/Android.bp tests/jdwp/Android.bp tests/jdwp/runner/device-side/Android.bp tests/jdwp/runner/host-side/Android.bp tests/leanbackjank/Android.bp tests/leanbackjank/app/Android.bp tests/libcore/jsr166/Android.bp tests/libcore/luni/Android.bp tests/libcore/ojluni/Android.bp tests/libcore/okhttp/Android.bp tests/libcore/runner/Android.bp tests/libcore/wycheproof-bc/Android.bp tests/libcore/wycheproof/Android.bp tests/location/common/Android.bp tests/location/location_coarse/Android.bp tests/location/location_fine/Android.bp tests/location/location_gnss/Android.bp tests/location/location_none/Android.bp tests/location/location_privileged/Android.bp tests/media/Android.bp tests/media/jni/Android.bp tests/mocking/Android.bp tests/mocking/debuggable/Android.bp tests/mocking/extended/Android.bp tests/mocking/inline/Android.bp tests/netlegacy22.permission/Android.bp tests/netsecpolicy/Android.bp tests/openglperf2/jni/Android.bp tests/pdf/Android.bp tests/providerui/Android.bp tests/quickaccesswallet/Android.bp tests/rollback/Android.bp tests/sample/Android.bp tests/security/Android.bp tests/sensor/Android.bp tests/signature/Android.bp tests/signature/api-check/Android.bp tests/signature/api-check/android-test-base-28-api/Android.bp tests/signature/api-check/android-test-base-current-api/Android.bp tests/signature/api-check/android-test-mock-current-api/Android.bp tests/signature/api-check/android-test-runner-current-api/Android.bp tests/signature/api-check/apache-http-legacy-27-api/Android.bp tests/signature/api-check/apache-http-legacy-current-api/Android.bp tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp tests/signature/api-check/current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-27-api/Android.bp tests/signature/api-check/hidden-api-blocklist-28-api/Android.bp tests/signature/api-check/hidden-api-blocklist-current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-debug-class/Android.bp tests/signature/api-check/hidden-api-blocklist-test-api/Android.bp tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp tests/signature/api-check/hidden-api-killswitch-sdklist/Android.bp tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp tests/signature/api-check/shared-libs-api/Android.mk tests/signature/api-check/system-annotation/Android.bp tests/signature/api-check/system-api/Android.mk tests/signature/dex-checker/Android.bp tests/signature/intent-check/Android.bp tests/signature/lib/android/Android.bp tests/signature/lib/common/Android.bp tests/signature/tests/Android.bp tests/simplecpu/jni/Android.bp tests/suspendapps/Android.bp tests/suspendapps/permission/Android.bp tests/suspendapps/test-apps/SuspendTestApp/Android.bp tests/suspendapps/test-apps/TestDeviceAdmin/Android.bp tests/suspendapps/tests/Android.bp tests/tests/accounts/Android.bp tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.bp tests/tests/accounts/common/Android.bp tests/tests/animation/Android.bp tests/tests/apache-http/Android.bp tests/tests/app.usage/Android.bp tests/tests/app.usage/TestApp1/Android.bp tests/tests/app/Android.bp tests/tests/appcomponentfactory/Android.bp tests/tests/appenumeration/Android.bp tests/tests/appenumeration/app/source/Android.bp tests/tests/appenumeration/app/target/Android.bp tests/tests/appenumeration/lib/Android.bp tests/tests/appop/Android.bp tests/tests/appop/AppInBackground/Android.bp tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp tests/tests/appop/AppThatUsesAppOps/Android.bp tests/tests/appop/AppToBlame1/Android.bp tests/tests/appop/AppToBlame2/Android.bp tests/tests/appop/AppToCollect/Android.bp tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp tests/tests/appop/AppWithDuplicateAttribution/Android.bp tests/tests/appop/AppWithLongAttributionTag/Android.bp tests/tests/appop/AppWithTooManyAttributions/Android.bp tests/tests/appop/aidl/AppOpsForegroundControlService/Android.bp tests/tests/appop/aidl/AppOpsUserService/Android.bp tests/tests/appop/appopsTestUtilLib/Android.bp tests/tests/appwidget/Android.bp tests/tests/appwidget/packages/launchermanifest/Android.bp tests/tests/appwidget/packages/widgetprovider/Android.bp tests/tests/assist/Android.bp tests/tests/assist/common/Android.bp tests/tests/assist/service/Android.bp tests/tests/assist/testapp/Android.bp tests/tests/background/Android.bp tests/tests/batterysaving/Android.bp tests/tests/batterysaving/apps/app_target_api_25/Android.bp tests/tests/batterysaving/apps/app_target_api_current/Android.bp tests/tests/batterysaving/common/Android.bp tests/tests/binder_ndk/Android.bp tests/tests/binder_ndk/libbinder_ndk_test/Android.bp tests/tests/bionic/Android.mk tests/tests/bionic_app/Android.bp tests/tests/bluetooth/Android.bp tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp tests/tests/calendarcommon/Android.bp tests/tests/calendarprovider/Android.bp tests/tests/car/Android.bp tests/tests/carrierapi/Android.bp tests/tests/classloaderfactory/Android.bp tests/tests/classloaderfactory/test-memcl/Android.bp tests/tests/classloaderfactory/test-pathcl/Android.bp tests/tests/colormode/Android.bp tests/tests/contactsprovider/Android.bp tests/tests/contactsprovider/gal/Android.bp tests/tests/contactsproviderwipe/Android.bp tests/tests/content/Android.bp tests/tests/content/BinderPermissionTestService/Android.bp tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.bp tests/tests/content/DirectBootUnawareTestApp/Android.bp tests/tests/content/HelloWorldApp/Android.bp tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp tests/tests/content/SyncAccountAccessStubs/Android.bp tests/tests/content/emptytestapp/Android.bp tests/tests/content/jni/Android.bp tests/tests/content/lib/accountaccess/Android.bp tests/tests/content/pm/SecureFrp/Android.bp tests/tests/cronet/Android.bp tests/tests/database/Android.bp tests/tests/database/apps/Android.bp tests/tests/deviceconfig/Android.bp tests/tests/display/Android.bp tests/tests/dpi/Android.bp tests/tests/dpi2/Android.bp tests/tests/dreams/Android.bp tests/tests/drm/Android.bp tests/tests/drm/jni/Android.bp tests/tests/drm/lib/Android.bp tests/tests/dynamic_linker/Android.bp tests/tests/effect/Android.bp tests/tests/externalservice/Android.bp tests/tests/externalservice/common/Android.bp tests/tests/externalservice/service/Android.bp tests/tests/gesture/Android.bp tests/tests/graphics/Android.bp tests/tests/graphics/jni/Android.bp tests/tests/gwp-asan/enabled/Android.bp tests/tests/hardware/Android.bp tests/tests/hardware/jni/Android.bp tests/tests/icu/Android.bp tests/tests/icu/icu4c_testapp/Android.bp tests/tests/identity/Android.bp tests/tests/instantapp/Android.bp tests/tests/jni/Android.bp tests/tests/jni/libjnicommon/Android.bp tests/tests/jni/libjnitest/Android.bp tests/tests/jvmti/attaching/Android.bp tests/tests/jvmti/attaching/jni/Android.bp tests/tests/keystore/Android.bp tests/tests/libcoreapievolution/Android.bp tests/tests/libcorefileio/Android.bp tests/tests/libcorelegacy22/Android.bp tests/tests/libnativehelper/Android.bp tests/tests/libnativehelper/jni/Android.bp tests/tests/libthermalndk/Android.bp tests/tests/libthermalndk/jni/Android.bp tests/tests/match_flags/Android.bp tests/tests/match_flags/app/a/Android.bp tests/tests/match_flags/app/b/Android.bp tests/tests/media/libaudiojni/Android.bp tests/tests/media/libimagereaderjni/Android.bp tests/tests/media/libndkaudio/Android.bp tests/tests/mediaparser/Android.bp tests/tests/mediastress/Android.bp tests/tests/mediastress/jni/Android.bp tests/tests/midi/Android.bp tests/tests/mimemap/Android.bp tests/tests/multiuser/Android.bp tests/tests/nativehardware/Android.bp tests/tests/nativehardware/jni/Android.bp tests/tests/nativemedia/aaudio/jni/Android.mk tests/tests/nativemedia/mediametrics/Android.bp tests/tests/nativemedia/sl/Android.mk tests/tests/nativemedia/xa/Android.mk tests/tests/nativemidi/jni/Android.mk tests/tests/ndef/Android.bp tests/tests/netpermission/internetpermission/Android.bp tests/tests/netpermission/updatestatspermission/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-false/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-true/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.bp tests/tests/networksecurityconfig/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.bp tests/tests/neuralnetworks/Android.mk tests/tests/neuralnetworks/tflite_delegate/Android.mk tests/tests/nfc/Android.bp tests/tests/notificationlegacy/notificationlegacy20/Android.bp tests/tests/notificationlegacy/notificationlegacy27/Android.bp tests/tests/notificationlegacy/notificationlegacy28/Android.bp tests/tests/notificationlegacy/notificationlegacy29/Android.bp tests/tests/opengl/Android.bp tests/tests/opengl/libopengltest/Android.bp tests/tests/openglperf/Android.bp tests/tests/openglperf/jni/Android.bp tests/tests/os/Android.bp tests/tests/os/Android.mk tests/tests/os/AutoRevokeDummyApp/Android.bp tests/tests/os/AutoRevokePreRApp/Android.bp tests/tests/os/jni/Android.bp tests/tests/packageinstaller/adminpackageinstaller/Android.bp tests/tests/packageinstaller/atomicinstall/Android.bp tests/tests/packageinstaller/emptytestapp/Android.bp tests/tests/packageinstaller/install/Android.bp tests/tests/packageinstaller/install_appop_default/Android.bp tests/tests/packageinstaller/install_appop_denied/Android.bp tests/tests/packageinstaller/nopermission/Android.bp tests/tests/packageinstaller/nopermission25/Android.bp tests/tests/packageinstaller/tapjacking/Android.bp tests/tests/packageinstaller/uninstall/Android.bp tests/tests/packagewatchdog/Android.bp tests/tests/permission/Android.bp tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp tests/tests/permission/AppThatRequestContactsPermission15/Android.bp tests/tests/permission/AppThatRequestContactsPermission16/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission22/Android.bp tests/tests/permission/AppThatRequestLocationPermission28/Android.bp tests/tests/permission/AppThatRequestLocationPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp tests/tests/permission/AppThatRequestOneTimePermission/Android.bp tests/tests/permission/AppThatRequestPermissionAandB/Android.bp tests/tests/permission/AppThatRequestPermissionAandC/Android.bp tests/tests/permission/AppThatRequestStoragePermission28/Android.bp tests/tests/permission/AppThatRequestStoragePermission29/Android.bp tests/tests/permission/AppThatRunsRationaleTests/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp tests/tests/permission/jni/Android.bp tests/tests/permission/permissionTestUtilLib/Android.bp tests/tests/permission/sdk28/Android.bp tests/tests/permission/telephony/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp tests/tests/permission2/Android.bp tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp tests/tests/permission3/Android.bp tests/tests/permission3/PermissionEscalationAppNonRuntime/Android.bp tests/tests/permission3/PermissionEscalationAppRuntime/Android.bp tests/tests/permission3/PermissionPolicyApp25/Android.bp tests/tests/permission3/UsePermissionApp22/Android.bp tests/tests/permission3/UsePermissionApp22CalendarOnly/Android.bp tests/tests/permission3/UsePermissionApp23/Android.bp tests/tests/permission3/UsePermissionApp25/Android.bp tests/tests/permission3/UsePermissionApp26/Android.bp tests/tests/permission3/UsePermissionApp28/Android.bp tests/tests/permission3/UsePermissionApp29/Android.bp tests/tests/permission3/UsePermissionAppLatest/Android.bp tests/tests/permission3/UsePermissionAppLatestWithBackground/Android.bp tests/tests/permission3/UsePermissionAppWithOverlay/Android.bp tests/tests/permission4/Android.bp tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp tests/tests/preference/Android.bp tests/tests/print/Android.bp tests/tests/print/ExternalPrintService/Android.bp tests/tests/print/printTestUtilLib/Android.bp tests/tests/proto/Android.bp tests/tests/provider/Android.bp tests/tests/provider/app/GalleryTestApp/Android.bp tests/tests/provider/preconditions/Android.bp tests/tests/renderscript/libcoremathtestcpp/Android.bp tests/tests/resolverservice/Android.bp tests/tests/resourcesloader/Android.bp tests/tests/resourcesloader/resources/Android.bp tests/tests/role/Android.bp tests/tests/role/CtsRoleTestApp/Android.bp tests/tests/role/CtsRoleTestApp28/Android.bp tests/tests/rsblas/libbnnmdata/Android.bp tests/tests/rscpp/librscpptest/Android.mk tests/tests/sax/Android.bp tests/tests/secure_element/access_control/AccessControlApp1/Android.bp tests/tests/secure_element/access_control/AccessControlApp2/Android.bp tests/tests/secure_element/access_control/AccessControlApp3/Android.bp tests/tests/secure_element/omapi/Android.bp tests/tests/security/Android.bp tests/tests/security/jni/Android.bp tests/tests/security/native/encryption/Android.bp tests/tests/security/native/verified_boot/Android.bp tests/tests/security/testeffect/Android.bp tests/tests/selinux/common/jni/Android.bp tests/tests/selinux/selinuxEphemeral/Android.bp tests/tests/selinux/selinuxTargetSdk25/Android.bp tests/tests/selinux/selinuxTargetSdk27/Android.bp tests/tests/selinux/selinuxTargetSdk28/Android.bp tests/tests/selinux/selinuxTargetSdk29/Android.bp tests/tests/selinux/selinuxTargetSdkCurrent/Android.bp tests/tests/settings/Android.bp tests/tests/sharesheet/Android.bp tests/tests/sharesheet/packages/Android.bp tests/tests/shortcutmanager/Android.bp tests/tests/simphonebookprovider/Android.bp tests/tests/simphonebookprovider/nosim/Android.bp tests/tests/simpleperf/Android.mk tests/tests/simpleperf/CtsSimpleperfDebuggableApp/Android.bp tests/tests/simpleperf/CtsSimpleperfProfileableApp/Android.bp tests/tests/slice/Android.bp tests/tests/soundtrigger/Android.bp tests/tests/speech/Android.bp tests/tests/syncmanager/Android.bp tests/tests/syncmanager/apps/Android.bp tests/tests/syncmanager/common/Android.bp tests/tests/systemintents/Android.bp tests/tests/systemui/Android.bp tests/tests/telecom/Android.bp tests/tests/telecom/Api29InCallServiceTestApp/Android.bp tests/tests/telecom/CallRedirectionServiceTestApp/Android.bp tests/tests/telecom/CallScreeningServiceTestApp/Android.bp tests/tests/telecom/CarModeTestApp/Android.bp tests/tests/telecom/CarModeTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyDialerTestApp/Android.bp tests/tests/telecom/ThirdPtyDialerTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyInCallServiceTestApp/Android.bp tests/tests/telecom2/Android.bp tests/tests/telecom3/Android.bp tests/tests/telephony/TestFinancialSmsApp/Android.bp tests/tests/telephony/TestSmsApp/Android.bp tests/tests/telephony/TestSmsApp22/Android.bp tests/tests/telephony/TestSmsRetrieverApp/Android.bp tests/tests/telephony/current/Android.bp tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp tests/tests/telephony/current/permissions/Android.bp tests/tests/telephony/current/preconditions/Android.bp tests/tests/telephony/current/preconditions/app/Android.bp tests/tests/telephony/current/src/android/telephony/cts/util/Android.bp tests/tests/telephony/sdk28/Android.bp tests/tests/telephony2/Android.bp tests/tests/telephony3/Android.bp tests/tests/telephony4/Android.bp tests/tests/telephonyprovider/Android.bp tests/tests/text/Android.bp tests/tests/text/jni/Android.bp tests/tests/textclassifier/Android.bp tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp tests/tests/theme/Android.bp tests/tests/toast/Android.bp tests/tests/toastlegacy/Android.bp tests/tests/tools/processors/view_inspector/Android.bp tests/tests/transition/Android.bp tests/tests/tv/Android.bp tests/tests/uiautomation/Android.bp tests/tests/uidisolation/Android.bp tests/tests/uirendering/Android.bp tests/tests/uirendering27/Android.bp tests/tests/usb/Android.bp tests/tests/util/Android.bp tests/tests/vcn/Android.bp tests/tests/view/jni/Android.bp tests/tests/view/sdk28/Android.bp tests/tests/view/surfacevalidator/Android.mk tests/tests/voiceinteraction/Android.bp tests/tests/voiceinteraction/common/Android.bp tests/tests/voiceinteraction/service/Android.bp tests/tests/voiceinteraction/testapp/Android.bp tests/tests/voicesettings/Android.bp tests/tests/voicesettings/service/Android.bp tests/tests/webkit/Android.bp tests/tests/widget/Android.bp tests/tests/widget/app/Android.bp tests/tests/widget29/Android.bp tests/tests/wifi/Android.bp tests/tests/wifi/CtsWifiLocationTestApp/Android.bp tests/tvprovider/Android.bp tests/video/Android.bp tests/vr/Android.bp tests/vr/jni/Android.bp tools/cfassembler/Android.bp tools/cts-api-coverage/Android.bp tools/cts-device-info/jni/Android.bp tools/cts-dynamic-config/Android.mk tools/cts-holo-generation/Android.bp tools/cts-media-preparer-app/Android.bp tools/cts-preconditions/Android.bp tools/cts-tradefed/Android.bp tools/cts-tradefed/tests/Android.bp tools/device-setup/TestDeviceSetup/Android.bp tools/manifest-generator/Android.bp tools/manifest-generator/tests/Android.bp tools/release-parser/Android.bp tools/release-parser/tests/Android.bp tools/vm-tests-tf/Android.bp tools/vm-tests-tf/Android.mk tools/vm-tests-tf/targetprep/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/testserver/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY to: apps/CtsVerifier/Android.bp apps/CtsVerifier/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-MIT SPDX-license-identifier-NCSA legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CC-BY legacy_unencumbered to: tests/tests/media/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: hostsidetests/gputools/Android.bp hostsidetests/gputools/layers/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-NCSA to: hostsidetests/appsecurity/certs/Android.bp hostsidetests/appsecurity/certs/keysets/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/testdata/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestAppPrebuilt/Android.bp hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/Android.bp libs/runner/Android.bp tests/BlobStore/certs/Android.bp tests/signature/api/Android.bp tests/signature/api/Android.mk tests/tests/telephony4/certs/Android.bp Added SPDX-license-identifier-Apache-2.0 legacy_unencumbered to: tests/tests/media/libmediandkjni/Android.bp Added SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/dhrystone/Android.mk Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ic8cb360bb718dfc853494a63deb3faee25cc04f7 Merged-in: Ic8cb360bb718dfc853494a63deb3faee25cc04f7 --- Vcn/tests/cts/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 5666ee78a5..ecb1236b9b 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test { name: "CtsVcnTestCases", defaults: ["cts_defaults"], From e921c73e8c847c90abed1b49755b9f568e2ad5d3 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 10 Feb 2021 10:52:48 -0800 Subject: [PATCH 0079/1057] API: Expose VcnControlPlaneConfig Each VcnGatewayConnectionConfig must have a VcnControlPlaneConfig that contains all connection, authentication and authorization parameters required to establish a gateway connection. Bug: 163604823 Test: make update-api && make Change-Id: If4a58e7b0391b485ee7c4482d422bec5e6ba4148 --- .../src/android/net/vcn/VcnControlPlaneConfig.java | 2 -- .../src/android/net/vcn/VcnControlPlaneIkeConfig.java | 2 -- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 8 -------- 3 files changed, 12 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java index 0c6ccfee5d..92f6c44403 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java @@ -35,8 +35,6 @@ import java.util.Objects; * * @see VcnManager * @see VcnGatewayConnectionConfig - * - * @hide */ public abstract class VcnControlPlaneConfig { /** @hide */ diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java index 2f6e1f63b9..de086f63b1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java @@ -34,8 +34,6 @@ import java.util.Objects; * configuration, authentication and authorization parameters. * * @see VcnControlPlaneConfig - * - * @hide */ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName(); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 94dff9159b..9f83b21f0d 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -420,7 +420,6 @@ public final class VcnGatewayConnectionConfig { * * @param ctrlPlaneConfig the control plane configuration * @see VcnControlPlaneConfig - * @hide */ public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) { Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null"); @@ -428,13 +427,6 @@ public final class VcnGatewayConnectionConfig { mCtrlPlaneConfig = ctrlPlaneConfig; } - /** Construct a Builder object. */ - // TODO: Remove this constructor when #Builder(ctrlPlaneConfig) is exposed as public API. - // This constructor is created to avoid changing API shape in this CL - public Builder() { - mCtrlPlaneConfig = null; - } - /** * Add a capability that this VCN Gateway Connection will support. * From 7ad3c8dd2a13b1da97ce123d679081f1a8c33555 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 17:07:05 -0800 Subject: [PATCH 0080/1057] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/base Added SPDX-license-identifier-Apache-2.0 to: apct-tests/perftests/autofill/Android.bp apct-tests/perftests/blobstore/Android.bp apct-tests/perftests/core/Android.bp apct-tests/perftests/core/apps/overlay/Android.bp apct-tests/perftests/core/apps/reources_manager/Android.bp apct-tests/perftests/core/jni/Android.bp apct-tests/perftests/multiuser/Android.bp apct-tests/perftests/multiuser/apps/dummyapp/Android.bp apct-tests/perftests/packagemanager/Android.bp apct-tests/perftests/packagemanager/apps/query-all/Android.bp apct-tests/perftests/textclassifier/Android.bp apct-tests/perftests/utils/Android.bp apct-tests/perftests/windowmanager/Android.bp apex/Android.bp apex/blobstore/framework/Android.bp apex/blobstore/service/Android.bp apex/jobscheduler/framework/Android.bp apex/jobscheduler/service/Android.bp apex/media/Android.bp apex/media/aidl/Android.bp apex/media/framework/Android.bp cmds/am/Android.bp cmds/app_process/Android.bp cmds/appops/Android.bp cmds/appwidget/Android.bp cmds/backup/Android.bp cmds/bmgr/Android.bp cmds/bootanimation/Android.bp cmds/bu/Android.bp cmds/content/Android.bp cmds/dpm/Android.bp cmds/hid/Android.bp cmds/hid/jni/Android.bp cmds/idmap2/Android.bp cmds/ime/Android.bp cmds/incident/Android.bp cmds/incident_helper/Android.bp cmds/incidentd/Android.bp cmds/input/Android.bp cmds/interrupter/Android.bp cmds/locksettings/Android.bp cmds/pm/Android.bp cmds/requestsync/Android.bp cmds/screencap/Android.bp cmds/sm/Android.bp cmds/svc/Android.bp cmds/telecom/Android.bp cmds/uiautomator/Android.bp cmds/uiautomator/cmds/uiautomator/Android.bp cmds/uiautomator/instrumentation/Android.bp cmds/uiautomator/library/Android.bp cmds/vr/Android.bp cmds/wm/Android.bp config/Android.bp core/java/android/service/wallpaper/Android.bp core/jni/Android.bp core/sysprop/Android.bp core/tests/BroadcastRadioTests/Android.bp core/tests/ConnectivityManagerTest/Android.bp core/tests/PackageInstallerSessions/Android.bp core/tests/PlatformCompatFramework/Android.bp core/tests/bandwidthtests/Android.bp core/tests/benchmarks/Android.bp core/tests/bluetoothtests/Android.bp core/tests/bugreports/Android.bp core/tests/coretests/Android.bp core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp core/tests/coretests/BinderProxyCountingTestApp/Android.bp core/tests/coretests/BinderProxyCountingTestService/Android.bp core/tests/coretests/BstatsTestApp/Android.bp core/tests/coretests/DisabledTestApp/Android.bp core/tests/coretests/EnabledTestApp/Android.bp core/tests/coretests/aidl/Android.bp core/tests/coretests/apks/Android.bp core/tests/coretests/apks/install/Android.bp core/tests/coretests/apks/install_bad_dex/Android.bp core/tests/coretests/apks/install_complete_package_info/Android.bp core/tests/coretests/apks/install_decl_perm/Android.bp core/tests/coretests/apks/install_jni_lib/Android.bp core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp core/tests/coretests/apks/install_loc_auto/Android.bp core/tests/coretests/apks/install_loc_internal/Android.bp core/tests/coretests/apks/install_loc_sdcard/Android.bp core/tests/coretests/apks/install_loc_unspecified/Android.bp core/tests/coretests/apks/install_use_perm_good/Android.bp core/tests/coretests/apks/install_uses_feature/Android.bp core/tests/coretests/apks/install_verifier_bad/Android.bp core/tests/coretests/apks/install_verifier_good/Android.bp core/tests/coretests/apks/keyset/Android.bp core/tests/coretests/apks/locales/Android.bp core/tests/coretests/apks/overlay_config/Android.bp core/tests/coretests/apks/version/Android.bp core/tests/coretests/apks/version_nosys/Android.bp core/tests/featureflagtests/Android.bp core/tests/hdmitests/Android.bp core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp core/tests/hosttests/test-apps/NoLocTestApp/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/SharedUid/32/Android.bp core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/64/Android.bp core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp core/tests/hosttests/test-apps/SimpleTestApp/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp core/tests/mockingcoretests/Android.bp core/tests/notificationtests/Android.bp core/tests/overlaytests/device/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp core/tests/overlaytests/host/Android.bp core/tests/overlaytests/remount/Android.bp core/tests/overlaytests/remount/test-apps/Overlay/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp core/tests/overlaytests/remount/test-apps/Target/Android.bp core/tests/packagemanagertests/Android.bp core/tests/privacytests/Android.bp core/tests/screenshothelpertests/Android.bp core/tests/systemproperties/Android.bp core/tests/utillib/Android.bp core/tests/utiltests/Android.bp core/tests/utiltests/jni/Android.bp core/tests/uwbtests/Android.bp core/xsd/Android.bp core/xsd/vts/Android.bp data/etc/Android.bp data/etc/car/Android.bp data/fonts/Android.bp data/keyboards/Android.mk drm/jni/Android.bp errorprone/Android.bp graphics/proto/Android.bp keystore/Android.bp keystore/tests/Android.bp libs/WindowManager/Jetpack/Android.bp libs/WindowManager/Shell/Android.bp libs/WindowManager/Shell/tests/Android.bp libs/androidfw/Android.bp libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp libs/hostgraphics/Android.bp libs/incident/Android.bp libs/input/Android.bp libs/input/tests/Android.bp libs/protoutil/Android.bp libs/services/Android.bp libs/storage/Android.bp libs/usb/tests/AccessoryChat/Android.bp libs/usb/tests/AccessoryChat/accessorychat/Android.bp location/lib/Android.bp location/tests/Android.bp location/tests/locationtests/Android.bp lowpan/tests/Android.bp media/Android.bp media/java/Android.bp media/java/android/media/tv/tunerresourcemanager/Android.bp media/jni/Android.bp media/jni/audioeffect/Android.bp media/jni/soundpool/Android.bp media/jni/soundpool/tests/Android.bp media/lib/remotedisplay/Android.bp media/lib/signer/Android.bp media/lib/tvremote/Android.bp media/lib/tvremote/tests/Android.bp media/mca/filterfw/Android.bp media/mca/filterfw/native/Android.bp media/mca/filterpacks/Android.bp media/mca/samples/CameraEffectsRecordingSample/Android.bp media/mca/tests/Android.bp media/native/midi/Android.bp media/packages/BluetoothMidiService/Android.bp media/packages/BluetoothMidiService/tests/unit/Android.bp media/tests/AudioPolicyTest/Android.bp media/tests/CameraBrowser/Android.bp media/tests/EffectsTest/Android.bp media/tests/MediaDump/Android.bp media/tests/MediaFrameworkTest/Android.bp media/tests/MediaRouter/Android.bp media/tests/MtpTests/Android.bp media/tests/ScoAudioTest/Android.bp media/tests/SoundPoolTest/Android.bp media/tests/TunerTest/Android.bp media/tests/audiotests/Android.bp media/tests/players/Android.bp mime/Android.bp native/android/Android.bp native/graphics/jni/Android.bp native/webview/loader/Android.bp nfc-extras/Android.bp nfc-extras/tests/Android.bp packages/AppPredictionLib/Android.bp packages/BackupEncryption/Android.bp packages/BackupEncryption/test/robolectric-integration/Android.bp packages/BackupEncryption/test/robolectric/Android.bp packages/BackupEncryption/test/unittest/Android.bp packages/BackupRestoreConfirmation/Android.bp packages/CarSystemUI/Android.bp packages/CarrierDefaultApp/Android.bp packages/CarrierDefaultApp/tests/unit/Android.bp packages/CompanionDeviceManager/Android.bp packages/Connectivity/framework/Android.bp packages/Connectivity/service/Android.bp packages/CtsShim/Android.bp packages/CtsShim/build/Android.bp packages/CtsShim/build/jni/Android.bp packages/DynamicSystemInstallationService/Android.bp packages/DynamicSystemInstallationService/tests/Android.bp packages/EasterEgg/Android.bp packages/EncryptedLocalTransport/Android.bp packages/ExtShared/Android.bp packages/ExternalStorageProvider/Android.bp packages/ExternalStorageProvider/tests/Android.bp packages/FakeOemFeatures/Android.bp packages/FusedLocation/Android.bp packages/InputDevices/Android.bp packages/LocalTransport/Android.bp packages/PackageInstaller/Android.bp packages/PrintRecommendationService/Android.bp packages/PrintSpooler/Android.bp packages/PrintSpooler/jni/Android.bp packages/PrintSpooler/tests/outofprocess/Android.bp packages/SettingsLib/ActionBarShadow/Android.bp packages/SettingsLib/ActionButtonsPreference/Android.bp packages/SettingsLib/AdaptiveIcon/Android.bp packages/SettingsLib/Android.bp packages/SettingsLib/AppPreference/Android.bp packages/SettingsLib/BarChartPreference/Android.bp packages/SettingsLib/DisplayDensityUtils/Android.bp packages/SettingsLib/EntityHeaderWidgets/Android.bp packages/SettingsLib/HelpUtils/Android.bp packages/SettingsLib/LayoutPreference/Android.bp packages/SettingsLib/ProgressBar/Android.bp packages/SettingsLib/RadioButtonPreference/Android.bp packages/SettingsLib/RestrictedLockUtils/Android.bp packages/SettingsLib/SchedulesProvider/Android.bp packages/SettingsLib/SearchProvider/Android.bp packages/SettingsLib/SearchWidget/Android.bp packages/SettingsLib/SettingsSpinner/Android.bp packages/SettingsLib/SettingsTheme/Android.bp packages/SettingsLib/Tile/Android.bp packages/SettingsLib/Utils/Android.bp packages/SettingsLib/search/Android.bp packages/SettingsLib/tests/integ/Android.bp packages/SettingsLib/tests/robotests/Android.bp packages/SettingsProvider/Android.bp packages/SharedStorageBackup/Android.bp packages/Shell/Android.bp packages/Shell/tests/Android.bp packages/SimAppDialog/Android.bp packages/SoundPicker/Android.bp packages/StatementService/Android.bp packages/SystemUI/Android.bp packages/SystemUI/plugin/Android.bp packages/SystemUI/plugin/ExamplePlugin/Android.bp packages/SystemUI/plugin_core/Android.bp packages/SystemUI/shared/Android.bp packages/VpnDialogs/Android.bp packages/WAPPushManager/Android.bp packages/WAPPushManager/tests/Android.bp packages/WallpaperBackup/Android.bp packages/WallpaperCropper/Android.bp packages/overlays/Android.mk packages/overlays/tests/Android.bp packages/services/PacProcessor/Android.bp packages/services/PacProcessor/jni/Android.bp packages/services/Proxy/Android.bp proto/Android.bp rs/jni/Android.mk samples/demo/haptic-assessment/Android.bp sax/tests/saxtests/Android.bp services/Android.bp services/accessibility/Android.bp services/appprediction/Android.bp services/appwidget/Android.bp services/autofill/Android.bp services/backup/Android.bp services/backup/backuplib/Android.bp services/companion/Android.bp services/contentcapture/Android.bp services/contentsuggestions/Android.bp services/core/Android.bp services/core/java/com/android/server/vcn/Android.bp services/core/jni/Android.bp services/core/xsd/Android.bp services/core/xsd/vts/Android.bp services/coverage/Android.bp services/devicepolicy/Android.bp services/incremental/Android.bp services/midi/Android.bp services/net/Android.bp services/people/Android.bp services/print/Android.bp services/profcollect/Android.bp services/restrictions/Android.bp services/robotests/Android.bp services/robotests/backup/Android.bp services/systemcaptions/Android.bp services/tests/PackageManagerComponentOverrideTests/Android.bp services/tests/PackageManagerServiceTests/host/Android.bp services/tests/PackageManagerServiceTests/host/test-apps/Android.bp services/tests/mockingservicestests/Android.bp services/tests/rescueparty/Android.bp services/tests/servicestests/Android.bp services/tests/servicestests/aidl/Android.bp services/tests/servicestests/apks/Android.bp services/tests/servicestests/apks/install-split-base/Android.bp services/tests/servicestests/apks/install-split-feature-a/Android.bp services/tests/servicestests/apks/install_intent_filters/Android.bp services/tests/servicestests/apks/install_uses_sdk/Android.bp services/tests/servicestests/test-apps/ConnTestApp/Android.bp services/tests/servicestests/test-apps/JobTestApp/Android.bp services/tests/servicestests/test-apps/PackageParserApp/Android.bp services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp services/tests/servicestests/test-apps/SuspendTestApp/Android.bp services/tests/shortcutmanagerutils/Android.bp services/tests/uiservicestests/Android.bp services/tests/wmtests/Android.bp services/usage/Android.bp services/usb/Android.bp services/voiceinteraction/Android.bp services/wifi/Android.bp startop/apps/test/Android.bp startop/iorap/Android.bp startop/iorap/functional_tests/Android.bp startop/iorap/stress/Android.bp startop/iorap/tests/Android.bp startop/view_compiler/Android.bp startop/view_compiler/dex_builder_test/Android.bp test-base/hiddenapi/Android.bp test-mock/Android.bp test-runner/tests/Android.bp tests/AccessibilityEventsLogger/Android.bp tests/AccessoryDisplay/common/Android.bp tests/AccessoryDisplay/sink/Android.bp tests/AccessoryDisplay/source/Android.bp tests/ActivityManagerPerfTests/stub-app/Android.bp tests/ActivityManagerPerfTests/test-app/Android.bp tests/ActivityManagerPerfTests/tests/Android.bp tests/ActivityManagerPerfTests/utils/Android.bp tests/ActivityTests/Android.bp tests/ActivityViewTest/Android.bp tests/AmSlam/Android.bp tests/ApkVerityTest/Android.bp tests/ApkVerityTest/ApkVerityTestApp/Android.bp tests/ApkVerityTest/block_device_writer/Android.bp tests/AppLaunch/Android.bp tests/AppLaunchWear/Android.bp tests/AppResourcesLoaders/Android.bp tests/AppResourcesLoaders/Overlay/Android.bp tests/Assist/Android.bp tests/AutoVerify/app1/Android.bp tests/AutoVerify/app2/Android.bp tests/AutoVerify/app3/Android.bp tests/AutoVerify/app4/Android.bp tests/BackgroundDexOptServiceIntegrationTests/Android.bp tests/BandwidthTests/Android.bp tests/BatteryWaster/Android.bp tests/BiDiTests/Android.bp tests/BlobStoreTestUtils/Android.bp tests/BootImageProfileTest/Android.bp tests/BrowserPowerTest/Android.bp tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp tests/CameraPrewarmTest/Android.bp tests/Codegen/Android.bp tests/Compatibility/Android.bp tests/CoreTests/android/Android.bp tests/DataIdleTest/Android.bp tests/DozeTest/Android.bp tests/DpiTest/Android.bp tests/DynamicCodeLoggerIntegrationTests/Android.mk tests/FeatureSplit/base/Android.bp tests/FeatureSplit/feature1/Android.bp tests/FeatureSplit/feature2/Android.bp tests/FixVibrateSetting/Android.bp tests/FlickerTests/Android.bp tests/FlickerTests/test-apps/Android.bp tests/FlickerTests/test-apps/flickerapp/Android.bp tests/FrameworkPerf/Android.bp tests/GamePerformance/Android.bp tests/GridLayoutTest/Android.bp tests/HierarchyViewerTest/Android.bp tests/HugeBackup/Android.bp tests/HwAccelerationTest/Android.bp tests/Internal/Android.bp tests/JankBench/Android.bp tests/JobSchedulerPerfTests/Android.bp tests/JobSchedulerTestApp/Android.bp tests/LargeAssetTest/Android.bp tests/LegacyAssistant/Android.bp tests/LocalizationTest/Android.bp tests/LocationTracker/Android.bp tests/LotsOfApps/Android.bp tests/LowStorageTest/Android.bp tests/ManagedProfileLifecycleStressTest/Android.bp tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp tests/MemoryUsage/Android.bp tests/MirrorSurfaceTest/Android.bp tests/NativeProcessesMemoryTest/Android.bp tests/NetworkSecurityConfigTest/Android.bp tests/NullHomeTest/Android.bp tests/OdmApps/Android.bp tests/OdmApps/app/Android.bp tests/OdmApps/priv-app/Android.bp tests/OneMedia/Android.bp tests/PackageWatchdog/Android.bp tests/PlatformCompatGating/Android.bp tests/PlatformCompatGating/test-rules/Android.bp tests/ProtoInputStreamTests/Android.bp tests/RemoteDisplayProvider/Android.bp tests/RenderThreadTest/Android.bp tests/RollbackTest/Android.bp tests/SerialChat/Android.bp tests/ServiceCrashTest/Android.bp tests/SharedLibrary/client/Android.bp tests/SharedLibrary/lib/Android.bp tests/ShowWhenLockedApp/Android.bp tests/SmokeTest/Android.bp tests/SmokeTest/tests/Android.bp tests/SmokeTestApps/Android.bp tests/SoundTriggerTestApp/Android.bp tests/Split/Android.bp tests/StagedInstallTest/Android.bp tests/StatusBar/Android.bp tests/SurfaceComposition/Android.bp tests/SurfaceControlViewHostTest/Android.bp tests/SystemMemoryTest/device/Android.bp tests/SystemMemoryTest/host/Android.bp tests/SystemUIDemoModeController/Android.bp tests/TaskOrganizerTest/Android.bp tests/TelephonyCommonTests/Android.bp tests/TouchLatency/Android.bp tests/TransformTest/Android.bp tests/TtsTests/Android.bp tests/UiBench/Android.bp tests/UsageReportingTest/Android.bp tests/UsageStatsPerfTests/Android.bp tests/UsageStatsTest/Android.bp tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp tests/UsbManagerTests/Android.bp tests/UsbManagerTests/lib/Android.bp tests/UsbTests/Android.bp tests/UsesFeature2Test/Android.bp tests/VectorDrawableTest/Android.bp tests/VoiceEnrollment/Android.bp tests/VoiceInteraction/Android.bp tests/WallpaperTest/Android.bp tests/WindowAnimationJank/Android.bp tests/WindowInsetsTests/Android.bp tests/appwidgets/AppWidgetHostTest/Android.bp tests/appwidgets/AppWidgetProviderTest/Android.bp tests/backup/Android.mk tests/benchmarks/Android.bp tests/libs-permissions/Android.bp tests/net/Android.bp tests/net/common/Android.bp tests/net/deflake/Android.bp tests/net/integration/Android.bp tests/net/jni/Android.bp tests/net/smoketest/Android.bp tests/notification/Android.bp tests/permission/Android.bp tests/privapp-permissions/Android.bp tests/testables/Android.bp tests/testables/tests/Android.bp tests/utils/StubIME/Android.bp tests/utils/hostutils/Android.bp tests/utils/testutils/Android.bp tests/vcn/Android.bp tools/aapt/Android.bp tools/aapt2/Android.bp tools/aapt2/integration-tests/AutoVersionTest/Android.bp tools/aapt2/integration-tests/BasicTest/Android.bp tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk tools/aapt2/integration-tests/StaticLibTest/App/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp tools/aapt2/integration-tests/SymlinkTest/Android.bp tools/bit/Android.bp tools/codegen/Android.bp tools/dump-coverage/Android.bp tools/incident_report/Android.bp tools/incident_section_gen/Android.bp tools/lock_agent/Android.bp tools/locked_region_code_injection/Android.bp tools/obbtool/Android.bp tools/powermodel/Android.bp tools/preload-check/Android.bp tools/preload-check/device/Android.bp tools/preload/loadclass/Android.bp tools/processors/staledataclass/Android.bp tools/processors/view_inspector/Android.bp tools/protologtool/Android.bp tools/sdkparcelables/Android.bp tools/split-select/Android.bp tools/streaming_proto/Android.bp tools/validatekeymaps/Android.bp wifi/java/Android.bp wifi/tests/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/hwui/Android.bp native/webview/plat_support/Android.bp obex/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-CPL-1.0 SPDX-license-identifier-GPL SPDX-license-identifier-GPL-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS SPDX-license-identifier-W3C legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD legacy_unencumbered to: core/java/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CPL-1.0 to: test-base/Android.bp test-runner/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL to: core/res/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL-2.0 to: libs/usb/Android.bp libs/usb/tests/accessorytest/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: tools/preload/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS to: api/Android.bp boot/Android.bp cmds/device_config/Android.bp cmds/settings/Android.bp core/api/Android.bp core/tests/coretests/certs/Android.bp core/tests/overlaytests/remount/test-apps/certs/Android.bp core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp libs/tracingproxy/Android.bp services/startop/Android.bp test-legacy/Android.mk tests/ApkVerityTest/testdata/Android.bp tests/TransitionTests/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ib9737d8fb5ef5b90a2c14fe71f1a571079edcf02 --- Vcn/service-b/src/com/android/server/vcn/Android.bp | 11 ++++++++++- Vcn/tests/unit/Android.bp | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp index 5ed204fd76..ab5da3ee45 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Android.bp +++ b/Vcn/service-b/src/com/android/server/vcn/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "framework-vcn-util-sources", srcs: ["util/**/*.java"], -} \ No newline at end of file +} diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 1dedc19f0c..41f73cd9c7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -2,6 +2,15 @@ // Build FrameworksVcnTests package //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "FrameworksVcnTests", srcs: [ From 0f19c7161dc4df18423b416be87ea367ab617dbc Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 17 Feb 2021 12:04:21 -0800 Subject: [PATCH 0081/1057] Test building VcnGatewayConnectionConfig with VcnControlPlaneIkeConfig This CL reflects the current API shape that requires a VcnControlPlaneConfig to construct a VcnGatewayConnectionConfig object. Bug: 163604823 Bug: 180561378 Test: atest CtsVcnTestCases:VcnManagerTest Change-Id: If86b482c573aca3c0d12d0123fc789008d0227f8 --- .../android/net/vcn/cts/VcnManagerTest.java | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 8f2c3a6c48..b92f079120 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -18,12 +18,24 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.SaProposal; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.os.ParcelUuid; @@ -50,12 +62,14 @@ public class VcnManagerTest { private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; + private final ConnectivityManager mConnectivityManager; public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); mVcnManager = mContext.getSystemService(VcnManager.class); mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); } @Before @@ -64,8 +78,43 @@ public class VcnManagerTest { } private VcnConfig buildVcnConfig() { + final IkeSaProposal ikeProposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addDhGroup(DH_GROUP_2048_BIT_MODP) + .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) + .build(); + + final String serverHostname = "2001:db8:1::100"; + final String testLocalId = "test.client.com"; + final String testRemoteId = "test.server.com"; + final byte[] psk = "psk".getBytes(); + + // TODO: b/180521384: Build the IkeSessionParams without a Context when the no-arg + // IkeSessionParams.Builder constructor is exposed. + final IkeSessionParams ikeParams = + new IkeSessionParams.Builder(mContext) + .setServerHostname(serverHostname) + .addSaProposal(ikeProposal) + .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) + .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) + .setAuthPsk(psk) + .build(); + + final ChildSaProposal childProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .build(); + final TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); + + final VcnControlPlaneIkeConfig controlConfig = + new VcnControlPlaneIkeConfig(ikeParams, childParams); + final VcnGatewayConnectionConfig gatewayConnConfig = - new VcnGatewayConnectionConfig.Builder() + new VcnGatewayConnectionConfig.Builder(controlConfig) .addExposedCapability(NET_CAPABILITY_INTERNET) .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) .setRetryInterval( @@ -84,11 +133,23 @@ public class VcnManagerTest { @Test(expected = SecurityException.class) public void testSetVcnConfig_noCarrierPrivileges() throws Exception { + // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not + // require an active default network. + assertNotNull( + "You must have an active network connection to complete CTS", + mConnectivityManager.getActiveNetwork()); + mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig()); } @Test public void testSetVcnConfig_withCarrierPrivileges() throws Exception { + // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not + // require an active default network. + assertNotNull( + "You must have an active network connection to complete CTS", + mConnectivityManager.getActiveNetwork()); + final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { From 2bca49e979e9a4158308f64225132fc3f5e867ed Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 15:55:59 -0800 Subject: [PATCH 0082/1057] Define VcnNetworkPolicyListener for VCN transports. This CL defines VcnNetworkPolicyListener and VCN Network policy functions for VcnManager. Specifically, VcnNetworkPolicyListeners should be added and removed by Network factories as they bring up and teardown data Networks. VcnNetworkPolicyListeners are used by VcnManagementService to notify transports when they should re-query for their updated VcnNetworkPolicyResults - done via VcnManager#applyVcnNetworkPolicy. Policy results inform transports what the current NetworkCapabilities are based on their VCN policy, and also whether the transport should teardown and restart. Bug: 177020190 Test: atest FrameworksVcnTests Change-Id: Ide2c73025f4ffceabf7955f219a79be5a9bdc0d9 --- .../src/android/net/vcn/VcnManager.java | 163 ++++++++++++------ .../net/vcn/VcnNetworkPolicyResult.aidl | 20 +++ .../net/vcn/VcnNetworkPolicyResult.java | 109 ++++++++++++ .../net/vcn/VcnUnderlyingNetworkPolicy.java | 27 +-- .../vcn/VcnUnderlyingNetworkPolicyTest.java | 2 +- 5 files changed, 258 insertions(+), 63 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.aidl create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index aea0ea988f..1c21844abf 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -72,8 +72,7 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map< - VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + private static final Map REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +92,13 @@ public class VcnManager { } /** - * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map + public static Map getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -161,22 +160,15 @@ public class VcnManager { } } - // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi + // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using + // the new VcnNetworkPolicyListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener { - /** - * Notifies the implementation that the VCN's underlying Network policy has changed. - * - *

    After receiving this callback, implementations MUST poll VcnManager for the updated - * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy. - */ - void onPolicyChanged(); - } + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} /** * Add a listener for VCN-underlying network policy updates. @@ -185,29 +177,14 @@ public class VcnManager { * Listener * @param listener the VcnUnderlyingNetworkPolicyListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is - * already registered + * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already + * registered * @hide */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnUnderlyingNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { - requireNonNull(executor, "executor must not be null"); - requireNonNull(listener, "listener must not be null"); - - VcnUnderlyingNetworkPolicyListenerBinder binder = - new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); - if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { - throw new IllegalArgumentException( - "Attempting to add a listener that is already in use"); - } - - try { - mService.addVcnUnderlyingNetworkPolicyListener(binder); - } catch (RemoteException e) { - REGISTERED_POLICY_LISTENERS.remove(listener); - throw e.rethrowFromSystemServer(); - } + addVcnNetworkPolicyListener(executor, listener); } /** @@ -220,19 +197,7 @@ public class VcnManager { */ public void removeVcnUnderlyingNetworkPolicyListener( @NonNull VcnUnderlyingNetworkPolicyListener listener) { - requireNonNull(listener, "listener must not be null"); - - VcnUnderlyingNetworkPolicyListenerBinder binder = - REGISTERED_POLICY_LISTENERS.remove(listener); - if (binder == null) { - return; - } - - try { - mService.removeVcnUnderlyingNetworkPolicyListener(binder); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + removeVcnNetworkPolicyListener(listener); } /** @@ -266,6 +231,107 @@ public class VcnManager { } } + // TODO: make VcnNetworkPolicyListener @SystemApi + /** + * VcnNetworkPolicyListener is the interface through which internal system components can + * register to receive updates for VCN-underlying Network policies from the System Server. + * + * @hide + */ + public interface VcnNetworkPolicyListener { + /** + * Notifies the implementation that the VCN's underlying Network policy has changed. + * + *

    After receiving this callback, implementations should get the current {@link + * VcnNetworkPolicyResult} via {@link #applyVcnNetworkPolicy(NetworkCapabilities, + * LinkProperties)}. + */ + void onPolicyChanged(); + } + + /** + * Add a listener for VCN-underlying Network policy updates. + * + * @param executor the Executor that will be used for invoking all calls to the specified + * Listener + * @param listener the VcnNetworkPolicyListener to be added + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void addVcnNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { + requireNonNull(executor, "executor must not be null"); + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); + if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { + throw new IllegalStateException("listener is already registered with VcnManager"); + } + + try { + mService.addVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + REGISTERED_POLICY_LISTENERS.remove(listener); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove the specified VcnNetworkPolicyListener from VcnManager. + * + *

    If the specified listener is not currently registered, this is a no-op. + * + * @param listener the VcnNetworkPolicyListener that will be removed + * @hide + */ + public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + REGISTERED_POLICY_LISTENERS.remove(listener); + if (binder == null) { + return; + } + + try { + mService.removeVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Applies the network policy for a {@link android.net.Network} with the given parameters. + * + *

    Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy + * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider + * MUST poll for the updated Network policy based on that Network's capabilities and properties. + * + * @param networkCapabilities the NetworkCapabilities to be used in determining the Network + * policy result for this Network. + * @param linkProperties the LinkProperties to be used in determining the Network policy result + * for this Network. + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @return the {@link VcnNetworkPolicyResult} to be used for this Network. + * @hide + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public VcnNetworkPolicyResult applyVcnNetworkPolicy( + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties) { + requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + requireNonNull(linkProperties, "linkProperties must not be null"); + + final VcnUnderlyingNetworkPolicy policy = + getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); + return new VcnNetworkPolicyResult( + policy.isTeardownRequested(), policy.getMergedNetworkCapabilities()); + } + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -415,18 +481,17 @@ public class VcnManager { } /** - * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System - * Server. + * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnUnderlyingNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnUnderlyingNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyListener listener) { mExecutor = executor; mListener = listener; } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.aidl b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.aidl new file mode 100644 index 0000000000..3f13abe869 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.aidl @@ -0,0 +1,20 @@ +/* + * 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 android.net.vcn; + +/** @hide */ +parcelable VcnNetworkPolicyResult; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java new file mode 100644 index 0000000000..8d011421cd --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -0,0 +1,109 @@ +/* + * 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 android.net.vcn; + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its + * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * + *

    Transports that are bringing up networks capable of acting as a VCN's underlying network + * should query for policy state upon any capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via VcnNetworkPolicyListener. + * + * @hide + */ +public final class VcnNetworkPolicyResult implements Parcelable { + private final boolean mIsTearDownRequested; + private final NetworkCapabilities mNetworkCapabilities; + + /** + * Constructs a VcnNetworkPolicyResult with the specified parameters. + * + * @hide + */ + public VcnNetworkPolicyResult( + boolean isTearDownRequested, @NonNull NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(networkCapabilities, "networkCapabilities must be non-null"); + + mIsTearDownRequested = isTearDownRequested; + mNetworkCapabilities = networkCapabilities; + } + + /** + * Returns whether this Carrier VCN policy policy result requires that the underlying Network + * should be torn down. + */ + public boolean isTeardownRequested() { + return mIsTearDownRequested; + } + + /** + * Returns the NetworkCapabilities with Carrier VCN policy bits applied to the provided + * capabilities. + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + @Override + public int hashCode() { + return Objects.hash(mIsTearDownRequested, mNetworkCapabilities); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VcnNetworkPolicyResult)) return false; + final VcnNetworkPolicyResult that = (VcnNetworkPolicyResult) o; + + return mIsTearDownRequested == that.mIsTearDownRequested + && mNetworkCapabilities.equals(that.mNetworkCapabilities); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsTearDownRequested); + dest.writeParcelable(mNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public VcnNetworkPolicyResult createFromParcel(Parcel in) { + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); + } + + public VcnNetworkPolicyResult[] newArray(int size) { + return new VcnNetworkPolicyResult[size]; + } + }; +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index dd7c86d87f..b47d564241 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -33,8 +33,7 @@ import java.util.Objects; * @hide */ public final class VcnUnderlyingNetworkPolicy implements Parcelable { - private final boolean mIsTearDownRequested; - private final NetworkCapabilities mMergedNetworkCapabilities; + private final VcnNetworkPolicyResult mVcnNetworkPolicyResult; /** * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters. @@ -46,8 +45,13 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { Objects.requireNonNull( mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull"); - mIsTearDownRequested = isTearDownRequested; - mMergedNetworkCapabilities = mergedNetworkCapabilities; + mVcnNetworkPolicyResult = + new VcnNetworkPolicyResult(isTearDownRequested, mergedNetworkCapabilities); + } + + private VcnUnderlyingNetworkPolicy(@NonNull VcnNetworkPolicyResult vcnNetworkPolicyResult) { + this.mVcnNetworkPolicyResult = + Objects.requireNonNull(vcnNetworkPolicyResult, "vcnNetworkPolicyResult"); } /** @@ -55,7 +59,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { * be torn down. */ public boolean isTeardownRequested() { - return mIsTearDownRequested; + return mVcnNetworkPolicyResult.isTeardownRequested(); } /** @@ -64,12 +68,12 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { */ @NonNull public NetworkCapabilities getMergedNetworkCapabilities() { - return mMergedNetworkCapabilities; + return mVcnNetworkPolicyResult.getNetworkCapabilities(); } @Override public int hashCode() { - return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities); + return Objects.hash(mVcnNetworkPolicyResult); } @Override @@ -78,8 +82,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false; final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o; - return mIsTearDownRequested == that.mIsTearDownRequested - && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities); + return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult); } /** {@inheritDoc} */ @@ -91,16 +94,14 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { /** {@inheritDoc} */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeBoolean(mIsTearDownRequested); - dest.writeParcelable(mMergedNetworkCapabilities, flags); + dest.writeParcelable(mVcnNetworkPolicyResult, flags); } /** Implement the Parcelable interface */ public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy( - in.readBoolean(), in.readParcelable(null)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java index 3ba0a1f53a..a674425efe 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -46,6 +46,6 @@ public class VcnUnderlyingNetworkPolicyTest { @Test public void testParcelUnparcel() { - assertParcelSane(SAMPLE_NETWORK_POLICY, 2); + assertParcelSane(SAMPLE_NETWORK_POLICY, 1); } } From 9d87db94c180011e0a5f77409f58a324c5e51481 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 18:49:23 -0800 Subject: [PATCH 0083/1057] Change Exception class references to use Class.getName(). This CL updates references to fully qualified Exception names (such as "java.lang.RuntimeException") to get the Exception name through the Exception's Class Object (e.g. RuntimeException.class.getName()). Bug: 163433613 Test: atest FrameworksVcntests Change-Id: I1ceccedda0a513a8c41caaef752d9f0005eceac0 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 6 +++--- Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 9ee072ee7c..06748a3aa2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -969,7 +969,7 @@ public class VcnGatewayConnection extends StateMachine { mGatewayStatusCallback.onGatewayConnectionError( mConnectionConfig.getRequiredUnderlyingCapabilities(), VCN_ERROR_CODE_INTERNAL_ERROR, - "java.lang.RuntimeException", + RuntimeException.class.getName(), "Received " + exception.getClass().getSimpleName() + " with message: " @@ -991,11 +991,11 @@ public class VcnGatewayConnection extends StateMachine { } else if (exception instanceof IkeInternalException && exception.getCause() instanceof IOException) { errorCode = VCN_ERROR_CODE_NETWORK_ERROR; - exceptionClass = "java.io.IOException"; + exceptionClass = IOException.class.getName(); exceptionMessage = exception.getCause().getMessage(); } else { errorCode = VCN_ERROR_CODE_INTERNAL_ERROR; - exceptionClass = "java.lang.RuntimeException"; + exceptionClass = RuntimeException.class.getName(); exceptionMessage = "Received " + exception.getClass().getSimpleName() diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 7087676055..ce8a898de2 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -207,7 +207,7 @@ public class VcnManagerTest { cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, - "java.net.UnknownHostException", + UnknownHostException.class.getName(), "exception_message"); verify(mMockStatusCallback) .onGatewayConnectionError( From 3ad5bae11572e41cf35eeaa28dee7e8cf24e831b Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 17:07:05 -0800 Subject: [PATCH 0084/1057] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/base Added SPDX-license-identifier-Apache-2.0 to: apct-tests/perftests/autofill/Android.bp apct-tests/perftests/blobstore/Android.bp apct-tests/perftests/core/Android.bp apct-tests/perftests/core/apps/overlay/Android.bp apct-tests/perftests/core/apps/reources_manager/Android.bp apct-tests/perftests/core/jni/Android.bp apct-tests/perftests/multiuser/Android.bp apct-tests/perftests/multiuser/apps/dummyapp/Android.bp apct-tests/perftests/packagemanager/Android.bp apct-tests/perftests/packagemanager/apps/query-all/Android.bp apct-tests/perftests/textclassifier/Android.bp apct-tests/perftests/utils/Android.bp apct-tests/perftests/windowmanager/Android.bp apex/Android.bp apex/blobstore/framework/Android.bp apex/blobstore/service/Android.bp apex/jobscheduler/framework/Android.bp apex/jobscheduler/service/Android.bp apex/media/Android.bp apex/media/aidl/Android.bp apex/media/framework/Android.bp cmds/am/Android.bp cmds/app_process/Android.bp cmds/appops/Android.bp cmds/appwidget/Android.bp cmds/backup/Android.bp cmds/bmgr/Android.bp cmds/bootanimation/Android.bp cmds/bu/Android.bp cmds/content/Android.bp cmds/dpm/Android.bp cmds/hid/Android.bp cmds/hid/jni/Android.bp cmds/idmap2/Android.bp cmds/ime/Android.bp cmds/incident/Android.bp cmds/incident_helper/Android.bp cmds/incidentd/Android.bp cmds/input/Android.bp cmds/interrupter/Android.bp cmds/locksettings/Android.bp cmds/pm/Android.bp cmds/requestsync/Android.bp cmds/screencap/Android.bp cmds/sm/Android.bp cmds/svc/Android.bp cmds/telecom/Android.bp cmds/uiautomator/Android.bp cmds/uiautomator/cmds/uiautomator/Android.bp cmds/uiautomator/instrumentation/Android.bp cmds/uiautomator/library/Android.bp cmds/vr/Android.bp cmds/wm/Android.bp config/Android.bp core/java/android/service/wallpaper/Android.bp core/jni/Android.bp core/sysprop/Android.bp core/tests/BroadcastRadioTests/Android.bp core/tests/ConnectivityManagerTest/Android.bp core/tests/PackageInstallerSessions/Android.bp core/tests/PlatformCompatFramework/Android.bp core/tests/bandwidthtests/Android.bp core/tests/benchmarks/Android.bp core/tests/bluetoothtests/Android.bp core/tests/bugreports/Android.bp core/tests/coretests/Android.bp core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp core/tests/coretests/BinderProxyCountingTestApp/Android.bp core/tests/coretests/BinderProxyCountingTestService/Android.bp core/tests/coretests/BstatsTestApp/Android.bp core/tests/coretests/DisabledTestApp/Android.bp core/tests/coretests/EnabledTestApp/Android.bp core/tests/coretests/aidl/Android.bp core/tests/coretests/apks/Android.bp core/tests/coretests/apks/install/Android.bp core/tests/coretests/apks/install_bad_dex/Android.bp core/tests/coretests/apks/install_complete_package_info/Android.bp core/tests/coretests/apks/install_decl_perm/Android.bp core/tests/coretests/apks/install_jni_lib/Android.bp core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp core/tests/coretests/apks/install_loc_auto/Android.bp core/tests/coretests/apks/install_loc_internal/Android.bp core/tests/coretests/apks/install_loc_sdcard/Android.bp core/tests/coretests/apks/install_loc_unspecified/Android.bp core/tests/coretests/apks/install_use_perm_good/Android.bp core/tests/coretests/apks/install_uses_feature/Android.bp core/tests/coretests/apks/install_verifier_bad/Android.bp core/tests/coretests/apks/install_verifier_good/Android.bp core/tests/coretests/apks/keyset/Android.bp core/tests/coretests/apks/locales/Android.bp core/tests/coretests/apks/overlay_config/Android.bp core/tests/coretests/apks/version/Android.bp core/tests/coretests/apks/version_nosys/Android.bp core/tests/featureflagtests/Android.bp core/tests/hdmitests/Android.bp core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp core/tests/hosttests/test-apps/NoLocTestApp/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp core/tests/hosttests/test-apps/SharedUid/32/Android.bp core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/64/Android.bp core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/Android.bp core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp core/tests/hosttests/test-apps/SimpleTestApp/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp core/tests/mockingcoretests/Android.bp core/tests/notificationtests/Android.bp core/tests/overlaytests/device/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp core/tests/overlaytests/host/Android.bp core/tests/overlaytests/remount/Android.bp core/tests/overlaytests/remount/test-apps/Overlay/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp core/tests/overlaytests/remount/test-apps/Target/Android.bp core/tests/packagemanagertests/Android.bp core/tests/privacytests/Android.bp core/tests/screenshothelpertests/Android.bp core/tests/systemproperties/Android.bp core/tests/utillib/Android.bp core/tests/utiltests/Android.bp core/tests/utiltests/jni/Android.bp core/tests/uwbtests/Android.bp core/xsd/Android.bp core/xsd/vts/Android.bp data/etc/Android.bp data/etc/car/Android.bp data/fonts/Android.bp data/keyboards/Android.mk drm/jni/Android.bp errorprone/Android.bp graphics/proto/Android.bp keystore/Android.bp keystore/tests/Android.bp libs/WindowManager/Jetpack/Android.bp libs/WindowManager/Shell/Android.bp libs/WindowManager/Shell/tests/Android.bp libs/androidfw/Android.bp libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp libs/hostgraphics/Android.bp libs/incident/Android.bp libs/input/Android.bp libs/input/tests/Android.bp libs/protoutil/Android.bp libs/services/Android.bp libs/storage/Android.bp libs/usb/tests/AccessoryChat/Android.bp libs/usb/tests/AccessoryChat/accessorychat/Android.bp location/lib/Android.bp location/tests/Android.bp location/tests/locationtests/Android.bp lowpan/tests/Android.bp media/Android.bp media/java/Android.bp media/java/android/media/tv/tunerresourcemanager/Android.bp media/jni/Android.bp media/jni/audioeffect/Android.bp media/jni/soundpool/Android.bp media/jni/soundpool/tests/Android.bp media/lib/remotedisplay/Android.bp media/lib/signer/Android.bp media/lib/tvremote/Android.bp media/lib/tvremote/tests/Android.bp media/mca/filterfw/Android.bp media/mca/filterfw/native/Android.bp media/mca/filterpacks/Android.bp media/mca/samples/CameraEffectsRecordingSample/Android.bp media/mca/tests/Android.bp media/native/midi/Android.bp media/packages/BluetoothMidiService/Android.bp media/packages/BluetoothMidiService/tests/unit/Android.bp media/tests/AudioPolicyTest/Android.bp media/tests/CameraBrowser/Android.bp media/tests/EffectsTest/Android.bp media/tests/MediaDump/Android.bp media/tests/MediaFrameworkTest/Android.bp media/tests/MediaRouter/Android.bp media/tests/MtpTests/Android.bp media/tests/ScoAudioTest/Android.bp media/tests/SoundPoolTest/Android.bp media/tests/TunerTest/Android.bp media/tests/audiotests/Android.bp media/tests/players/Android.bp mime/Android.bp native/android/Android.bp native/graphics/jni/Android.bp native/webview/loader/Android.bp nfc-extras/Android.bp nfc-extras/tests/Android.bp packages/AppPredictionLib/Android.bp packages/BackupEncryption/Android.bp packages/BackupEncryption/test/robolectric-integration/Android.bp packages/BackupEncryption/test/robolectric/Android.bp packages/BackupEncryption/test/unittest/Android.bp packages/BackupRestoreConfirmation/Android.bp packages/CarSystemUI/Android.bp packages/CarrierDefaultApp/Android.bp packages/CarrierDefaultApp/tests/unit/Android.bp packages/CompanionDeviceManager/Android.bp packages/Connectivity/framework/Android.bp packages/Connectivity/service/Android.bp packages/CtsShim/Android.bp packages/CtsShim/build/Android.bp packages/CtsShim/build/jni/Android.bp packages/DynamicSystemInstallationService/Android.bp packages/DynamicSystemInstallationService/tests/Android.bp packages/EasterEgg/Android.bp packages/EncryptedLocalTransport/Android.bp packages/ExtShared/Android.bp packages/ExternalStorageProvider/Android.bp packages/ExternalStorageProvider/tests/Android.bp packages/FakeOemFeatures/Android.bp packages/FusedLocation/Android.bp packages/InputDevices/Android.bp packages/LocalTransport/Android.bp packages/PackageInstaller/Android.bp packages/PrintRecommendationService/Android.bp packages/PrintSpooler/Android.bp packages/PrintSpooler/jni/Android.bp packages/PrintSpooler/tests/outofprocess/Android.bp packages/SettingsLib/ActionBarShadow/Android.bp packages/SettingsLib/ActionButtonsPreference/Android.bp packages/SettingsLib/AdaptiveIcon/Android.bp packages/SettingsLib/Android.bp packages/SettingsLib/AppPreference/Android.bp packages/SettingsLib/BarChartPreference/Android.bp packages/SettingsLib/DisplayDensityUtils/Android.bp packages/SettingsLib/EntityHeaderWidgets/Android.bp packages/SettingsLib/HelpUtils/Android.bp packages/SettingsLib/LayoutPreference/Android.bp packages/SettingsLib/ProgressBar/Android.bp packages/SettingsLib/RadioButtonPreference/Android.bp packages/SettingsLib/RestrictedLockUtils/Android.bp packages/SettingsLib/SchedulesProvider/Android.bp packages/SettingsLib/SearchProvider/Android.bp packages/SettingsLib/SearchWidget/Android.bp packages/SettingsLib/SettingsSpinner/Android.bp packages/SettingsLib/SettingsTheme/Android.bp packages/SettingsLib/Tile/Android.bp packages/SettingsLib/Utils/Android.bp packages/SettingsLib/search/Android.bp packages/SettingsLib/tests/integ/Android.bp packages/SettingsLib/tests/robotests/Android.bp packages/SettingsProvider/Android.bp packages/SharedStorageBackup/Android.bp packages/Shell/Android.bp packages/Shell/tests/Android.bp packages/SimAppDialog/Android.bp packages/SoundPicker/Android.bp packages/StatementService/Android.bp packages/SystemUI/Android.bp packages/SystemUI/plugin/Android.bp packages/SystemUI/plugin/ExamplePlugin/Android.bp packages/SystemUI/plugin_core/Android.bp packages/SystemUI/shared/Android.bp packages/VpnDialogs/Android.bp packages/WAPPushManager/Android.bp packages/WAPPushManager/tests/Android.bp packages/WallpaperBackup/Android.bp packages/WallpaperCropper/Android.bp packages/overlays/Android.mk packages/overlays/tests/Android.bp packages/services/PacProcessor/Android.bp packages/services/PacProcessor/jni/Android.bp packages/services/Proxy/Android.bp proto/Android.bp rs/jni/Android.mk samples/demo/haptic-assessment/Android.bp sax/tests/saxtests/Android.bp services/Android.bp services/accessibility/Android.bp services/appprediction/Android.bp services/appwidget/Android.bp services/autofill/Android.bp services/backup/Android.bp services/backup/backuplib/Android.bp services/companion/Android.bp services/contentcapture/Android.bp services/contentsuggestions/Android.bp services/core/Android.bp services/core/java/com/android/server/vcn/Android.bp services/core/jni/Android.bp services/core/xsd/Android.bp services/core/xsd/vts/Android.bp services/coverage/Android.bp services/devicepolicy/Android.bp services/incremental/Android.bp services/midi/Android.bp services/net/Android.bp services/people/Android.bp services/print/Android.bp services/profcollect/Android.bp services/restrictions/Android.bp services/robotests/Android.bp services/robotests/backup/Android.bp services/systemcaptions/Android.bp services/tests/PackageManagerComponentOverrideTests/Android.bp services/tests/PackageManagerServiceTests/host/Android.bp services/tests/PackageManagerServiceTests/host/test-apps/Android.bp services/tests/mockingservicestests/Android.bp services/tests/rescueparty/Android.bp services/tests/servicestests/Android.bp services/tests/servicestests/aidl/Android.bp services/tests/servicestests/apks/Android.bp services/tests/servicestests/apks/install-split-base/Android.bp services/tests/servicestests/apks/install-split-feature-a/Android.bp services/tests/servicestests/apks/install_intent_filters/Android.bp services/tests/servicestests/apks/install_uses_sdk/Android.bp services/tests/servicestests/test-apps/ConnTestApp/Android.bp services/tests/servicestests/test-apps/JobTestApp/Android.bp services/tests/servicestests/test-apps/PackageParserApp/Android.bp services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp services/tests/servicestests/test-apps/SuspendTestApp/Android.bp services/tests/shortcutmanagerutils/Android.bp services/tests/uiservicestests/Android.bp services/tests/wmtests/Android.bp services/usage/Android.bp services/usb/Android.bp services/voiceinteraction/Android.bp services/wifi/Android.bp startop/apps/test/Android.bp startop/iorap/Android.bp startop/iorap/functional_tests/Android.bp startop/iorap/stress/Android.bp startop/iorap/tests/Android.bp startop/view_compiler/Android.bp startop/view_compiler/dex_builder_test/Android.bp test-base/hiddenapi/Android.bp test-mock/Android.bp test-runner/tests/Android.bp tests/AccessibilityEventsLogger/Android.bp tests/AccessoryDisplay/common/Android.bp tests/AccessoryDisplay/sink/Android.bp tests/AccessoryDisplay/source/Android.bp tests/ActivityManagerPerfTests/stub-app/Android.bp tests/ActivityManagerPerfTests/test-app/Android.bp tests/ActivityManagerPerfTests/tests/Android.bp tests/ActivityManagerPerfTests/utils/Android.bp tests/ActivityTests/Android.bp tests/ActivityViewTest/Android.bp tests/AmSlam/Android.bp tests/ApkVerityTest/Android.bp tests/ApkVerityTest/ApkVerityTestApp/Android.bp tests/ApkVerityTest/block_device_writer/Android.bp tests/AppLaunch/Android.bp tests/AppLaunchWear/Android.bp tests/AppResourcesLoaders/Android.bp tests/AppResourcesLoaders/Overlay/Android.bp tests/Assist/Android.bp tests/AutoVerify/app1/Android.bp tests/AutoVerify/app2/Android.bp tests/AutoVerify/app3/Android.bp tests/AutoVerify/app4/Android.bp tests/BackgroundDexOptServiceIntegrationTests/Android.bp tests/BandwidthTests/Android.bp tests/BatteryWaster/Android.bp tests/BiDiTests/Android.bp tests/BlobStoreTestUtils/Android.bp tests/BootImageProfileTest/Android.bp tests/BrowserPowerTest/Android.bp tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp tests/CameraPrewarmTest/Android.bp tests/Codegen/Android.bp tests/Compatibility/Android.bp tests/CoreTests/android/Android.bp tests/DataIdleTest/Android.bp tests/DozeTest/Android.bp tests/DpiTest/Android.bp tests/DynamicCodeLoggerIntegrationTests/Android.mk tests/FeatureSplit/base/Android.bp tests/FeatureSplit/feature1/Android.bp tests/FeatureSplit/feature2/Android.bp tests/FixVibrateSetting/Android.bp tests/FlickerTests/Android.bp tests/FlickerTests/test-apps/Android.bp tests/FlickerTests/test-apps/flickerapp/Android.bp tests/FrameworkPerf/Android.bp tests/GamePerformance/Android.bp tests/GridLayoutTest/Android.bp tests/HierarchyViewerTest/Android.bp tests/HugeBackup/Android.bp tests/HwAccelerationTest/Android.bp tests/Internal/Android.bp tests/JankBench/Android.bp tests/JobSchedulerPerfTests/Android.bp tests/JobSchedulerTestApp/Android.bp tests/LargeAssetTest/Android.bp tests/LegacyAssistant/Android.bp tests/LocalizationTest/Android.bp tests/LocationTracker/Android.bp tests/LotsOfApps/Android.bp tests/LowStorageTest/Android.bp tests/ManagedProfileLifecycleStressTest/Android.bp tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp tests/MemoryUsage/Android.bp tests/MirrorSurfaceTest/Android.bp tests/NativeProcessesMemoryTest/Android.bp tests/NetworkSecurityConfigTest/Android.bp tests/NullHomeTest/Android.bp tests/OdmApps/Android.bp tests/OdmApps/app/Android.bp tests/OdmApps/priv-app/Android.bp tests/OneMedia/Android.bp tests/PackageWatchdog/Android.bp tests/PlatformCompatGating/Android.bp tests/PlatformCompatGating/test-rules/Android.bp tests/ProtoInputStreamTests/Android.bp tests/RemoteDisplayProvider/Android.bp tests/RenderThreadTest/Android.bp tests/RollbackTest/Android.bp tests/SerialChat/Android.bp tests/ServiceCrashTest/Android.bp tests/SharedLibrary/client/Android.bp tests/SharedLibrary/lib/Android.bp tests/ShowWhenLockedApp/Android.bp tests/SmokeTest/Android.bp tests/SmokeTest/tests/Android.bp tests/SmokeTestApps/Android.bp tests/SoundTriggerTestApp/Android.bp tests/Split/Android.bp tests/StagedInstallTest/Android.bp tests/StatusBar/Android.bp tests/SurfaceComposition/Android.bp tests/SurfaceControlViewHostTest/Android.bp tests/SystemMemoryTest/device/Android.bp tests/SystemMemoryTest/host/Android.bp tests/SystemUIDemoModeController/Android.bp tests/TaskOrganizerTest/Android.bp tests/TelephonyCommonTests/Android.bp tests/TouchLatency/Android.bp tests/TransformTest/Android.bp tests/TtsTests/Android.bp tests/UiBench/Android.bp tests/UsageReportingTest/Android.bp tests/UsageStatsPerfTests/Android.bp tests/UsageStatsTest/Android.bp tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp tests/UsbManagerTests/Android.bp tests/UsbManagerTests/lib/Android.bp tests/UsbTests/Android.bp tests/UsesFeature2Test/Android.bp tests/VectorDrawableTest/Android.bp tests/VoiceEnrollment/Android.bp tests/VoiceInteraction/Android.bp tests/WallpaperTest/Android.bp tests/WindowAnimationJank/Android.bp tests/WindowInsetsTests/Android.bp tests/appwidgets/AppWidgetHostTest/Android.bp tests/appwidgets/AppWidgetProviderTest/Android.bp tests/backup/Android.mk tests/benchmarks/Android.bp tests/libs-permissions/Android.bp tests/net/Android.bp tests/net/common/Android.bp tests/net/deflake/Android.bp tests/net/integration/Android.bp tests/net/jni/Android.bp tests/net/smoketest/Android.bp tests/notification/Android.bp tests/permission/Android.bp tests/privapp-permissions/Android.bp tests/testables/Android.bp tests/testables/tests/Android.bp tests/utils/StubIME/Android.bp tests/utils/hostutils/Android.bp tests/utils/testutils/Android.bp tests/vcn/Android.bp tools/aapt/Android.bp tools/aapt2/Android.bp tools/aapt2/integration-tests/AutoVersionTest/Android.bp tools/aapt2/integration-tests/BasicTest/Android.bp tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk tools/aapt2/integration-tests/StaticLibTest/App/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp tools/aapt2/integration-tests/SymlinkTest/Android.bp tools/bit/Android.bp tools/codegen/Android.bp tools/dump-coverage/Android.bp tools/incident_report/Android.bp tools/incident_section_gen/Android.bp tools/lock_agent/Android.bp tools/locked_region_code_injection/Android.bp tools/obbtool/Android.bp tools/powermodel/Android.bp tools/preload-check/Android.bp tools/preload-check/device/Android.bp tools/preload/loadclass/Android.bp tools/processors/staledataclass/Android.bp tools/processors/view_inspector/Android.bp tools/protologtool/Android.bp tools/sdkparcelables/Android.bp tools/split-select/Android.bp tools/streaming_proto/Android.bp tools/validatekeymaps/Android.bp wifi/java/Android.bp wifi/tests/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/hwui/Android.bp native/webview/plat_support/Android.bp obex/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-CPL-1.0 SPDX-license-identifier-GPL SPDX-license-identifier-GPL-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS SPDX-license-identifier-W3C legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD legacy_unencumbered to: core/java/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CPL-1.0 to: test-base/Android.bp test-runner/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL to: core/res/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-GPL-2.0 to: libs/usb/Android.bp libs/usb/tests/accessorytest/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: tools/preload/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS to: api/Android.bp boot/Android.bp cmds/device_config/Android.bp cmds/settings/Android.bp core/api/Android.bp core/tests/coretests/certs/Android.bp core/tests/overlaytests/remount/test-apps/certs/Android.bp core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp libs/tracingproxy/Android.bp services/startop/Android.bp test-legacy/Android.mk tests/ApkVerityTest/testdata/Android.bp tests/TransitionTests/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ib9737d8fb5ef5b90a2c14fe71f1a571079edcf02 Merged-In: Ib9737d8fb5ef5b90a2c14fe71f1a571079edcf02 --- Vcn/service-b/src/com/android/server/vcn/Android.bp | 11 ++++++++++- Vcn/tests/unit/Android.bp | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp index 5ed204fd76..ab5da3ee45 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Android.bp +++ b/Vcn/service-b/src/com/android/server/vcn/Android.bp @@ -1,4 +1,13 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "framework-vcn-util-sources", srcs: ["util/**/*.java"], -} \ No newline at end of file +} diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 1dedc19f0c..41f73cd9c7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -2,6 +2,15 @@ // Build FrameworksVcnTests package //######################################################################## +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "FrameworksVcnTests", srcs: [ From d94bdcd7de2cee3451f0445da4448d9da05b35ae Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 4 Feb 2021 13:42:31 -0800 Subject: [PATCH 0085/1057] Expose VCN Network policy APIs. This CL exposes APIs used for a) receiving VCN Network policy updates and b) applying VCN Network policies to a given Network. Specifically, these APIs should be used to receive notifications from VcnManager whenever a VCN Network policy may have changed - generally, following a VCN starting up, tearing down, or entering Safe Mode. When a VcnNetworkPolicyListener is notified of a policy change, the listener should query VcnManager#applyVcnNetworkPolicy to receive the updated VcnNetworkPolicyResult. This policy result informs the listener of their resulting NetworkCapabilities and also whether a Network teardown is required as a consequence of the policy change. Bug: 177020190 Test: atest FrameworksVcnTests Change-Id: Ied78a57973a4ceaa7ef4cd9feee64478137497b8 --- .../src/android/net/vcn/VcnManager.java | 20 ++++++++++++++++--- .../net/vcn/VcnNetworkPolicyResult.java | 19 +++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 1c21844abf..729e68a6a9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.net.LinkProperties; @@ -231,13 +232,20 @@ public class VcnManager { } } - // TODO: make VcnNetworkPolicyListener @SystemApi /** - * VcnNetworkPolicyListener is the interface through which internal system components can - * register to receive updates for VCN-underlying Network policies from the System Server. + * VcnNetworkPolicyListener is the interface through which internal system components (e.g. + * Network Factories) can register to receive updates for VCN-underlying Network policies from + * the System Server. + * + *

    Any Network Factory that brings up Networks capable of being VCN-underlying Networks + * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify + * the registrant when VCN Network policies change. Upon receiving this signal, the listener + * must check {@link VcnManager} for the current Network policy result for each of its Networks + * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. * * @hide */ + @SystemApi public interface VcnNetworkPolicyListener { /** * Notifies the implementation that the VCN's underlying Network policy has changed. @@ -252,6 +260,9 @@ public class VcnManager { /** * Add a listener for VCN-underlying Network policy updates. * + *

    A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is + * registered. No callbacks are guaranteed upon registration. + * * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnNetworkPolicyListener to be added @@ -259,6 +270,7 @@ public class VcnManager { * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { @@ -287,6 +299,7 @@ public class VcnManager { * @param listener the VcnNetworkPolicyListener that will be removed * @hide */ + @SystemApi public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { requireNonNull(listener, "listener must not be null"); @@ -319,6 +332,7 @@ public class VcnManager { * @hide */ @NonNull + @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public VcnNetworkPolicyResult applyVcnNetworkPolicy( @NonNull NetworkCapabilities networkCapabilities, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index 8d011421cd..5e93820063 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -17,6 +17,7 @@ package android.net.vcn; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.net.NetworkCapabilities; import android.os.Parcel; import android.os.Parcelable; @@ -27,12 +28,13 @@ import java.util.Objects; * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. * - *

    Transports that are bringing up networks capable of acting as a VCN's underlying network - * should query for policy state upon any capability changes (e.g. changing of TRUSTED bit), and - * when prompted by VcnManagementService via VcnNetworkPolicyListener. + *

    Bearers that are bringing up networks capable of acting as a VCN's underlying network should + * query for Network policy results upon any capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via {@link VcnManager.VcnNetworkPolicyListener}. * * @hide */ +@SystemApi public final class VcnNetworkPolicyResult implements Parcelable { private final boolean mIsTearDownRequested; private final NetworkCapabilities mNetworkCapabilities; @@ -51,16 +53,19 @@ public final class VcnNetworkPolicyResult implements Parcelable { } /** - * Returns whether this Carrier VCN policy policy result requires that the underlying Network - * should be torn down. + * Returns whether this VCN policy result requires that the underlying Network should be torn + * down. + * + *

    Upon querying for the current Network policy result, the bearer must check this method, + * and MUST tear down the corresponding Network if it returns true. */ public boolean isTeardownRequested() { return mIsTearDownRequested; } /** - * Returns the NetworkCapabilities with Carrier VCN policy bits applied to the provided - * capabilities. + * Returns the NetworkCapabilities that the bearer should be using for the corresponding + * Network. */ @NonNull public NetworkCapabilities getNetworkCapabilities() { From b14803f37d80ce76f55bcce66bbef76fb67abf35 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 18 Feb 2021 17:06:31 -0800 Subject: [PATCH 0086/1057] Define VcnStatusCallback#onVcnStatusChanged. This CL defines VcnStatusCallback#onVcnStatusChanged for notifying VcnStatusCallbacks when the status of their specified subscription group changes. Specifically, status codes will be provided to notify callbacks when a VCN is started, stopped, enters Safe Mode, and when there are no matching VCNs. Bug: 180659281 Test: atest FrameworksVcnTests Change-Id: Icf686c3da6c5bdeeab88f60495d2ad438fa15692 --- .../android/net/vcn/IVcnStatusCallback.aidl | 3 +- .../src/android/net/vcn/VcnManager.java | 73 ++++++++++++++++++- .../java/android/net/vcn/VcnManagerTest.java | 5 ++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl index 555e9b5883..d91cef592d 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl @@ -17,8 +17,9 @@ package android.net.vcn; /** @hide */ -interface IVcnStatusCallback { +oneway interface IVcnStatusCallback { void onEnteredSafeMode(); + void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, int errorCode, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 729e68a6a9..eb8c251fec 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -346,6 +346,56 @@ public class VcnManager { policy.isTeardownRequested(), policy.getMergedNetworkCapabilities()); } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + VCN_STATUS_CODE_NOT_CONFIGURED, + VCN_STATUS_CODE_INACTIVE, + VCN_STATUS_CODE_ACTIVE, + VCN_STATUS_CODE_SAFE_MODE + }) + public @interface VcnStatusCode {} + + /** + * Value indicating that the VCN for the subscription group is not configured, or that the + * callback is not privileged for the subscription group. + * + * @hide + */ + public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; + + /** + * Value indicating that the VCN for the subscription group is inactive. + * + *

    A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the + * provisioning package is not privileged. + * + * @hide + */ + public static final int VCN_STATUS_CODE_INACTIVE = 1; + + /** + * Value indicating that the VCN for the subscription group is active. + * + *

    A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning + * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered + * active while it is connecting, fully connected, and disconnecting. + * + * @hide + */ + public static final int VCN_STATUS_CODE_ACTIVE = 2; + + /** + * Value indicating that the VCN for the subscription group is in Safe Mode. + * + *

    A VCN will be put into Safe Mode if any of the gateway connections were unable to + * establish a connection within a system-determined timeout (while underlying networks were + * available). + * + * @hide + */ + public static final int VCN_STATUS_CODE_SAFE_MODE = 3; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -403,8 +453,18 @@ public class VcnManager { * *

    A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. + * + * @hide */ - public abstract void onEnteredSafeMode(); + public void onEnteredSafeMode() {} + + /** + * Invoked when status of the VCN for this callback's subscription group changes. + * + * @param statusCode the code for the status change encountered by this {@link + * VcnStatusCallback}'s subscription group. + */ + public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** * Invoked when a VCN Gateway Connection corresponding to this callback's subscription @@ -436,6 +496,11 @@ public class VcnManager { *

    A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + *

    {@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the + * current status for the specified subscription group's VCN. If the registrant is not + * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be + * returned. + * * @param subscriptionGroup The subscription group to match for callbacks * @param executor The {@link Executor} to be used for invoking callbacks * @param callback The VcnStatusCallback to be registered @@ -539,6 +604,12 @@ public class VcnManager { () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); } + @Override + public void onVcnStatusChanged(@VcnStatusCode int statusCode) { + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); + } + // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' @Override public void onGatewayConnectionError( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index ce8a898de2..66590c9257 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -16,6 +16,8 @@ package android.net.vcn; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; + import static androidx.test.InstrumentationRegistry.getContext; import static org.junit.Assert.assertEquals; @@ -204,6 +206,9 @@ public class VcnManagerTest { cbBinder.onEnteredSafeMode(); verify(mMockStatusCallback).onEnteredSafeMode(); + cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, From 0dc6ed1106d89d0878c87dc595b3af915c82b95c Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 19 Feb 2021 15:53:44 -0800 Subject: [PATCH 0087/1057] Notify VcnStatusCallback#onVcnStatusChanged for Safe Mode. This CL updates VcnManagementService to notify callbacks when VCNs enter Safe Mode via #onVcnStatusChanged. Callbacks were previously notified via #onEnteredSafeMode - however, VcnStatusCallbacks were changed to provide more status information by defining onVcnStatusChanged(int) per API Council feedback. Bug: 1597023 Test: atest FrameworksVcnTests Change-Id: I34ef76ec29f4369390449b70b37bc3cf99c09c77 --- .../src/com/android/server/VcnManagementService.java | 7 ++++++- .../com/android/server/VcnManagementServiceTest.java | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 329ab9983c..8d5d3d939e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; + import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -837,7 +839,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo)) { - Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); + Binder.withCleanCallingIdentity( + () -> + cbInfo.mCallback.onVcnStatusChanged( + VCN_STATUS_CODE_SAFE_MODE)); } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 45b2381ce0..9b500a7271 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -43,7 +43,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,6 +58,7 @@ import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.IBinder; @@ -783,7 +783,7 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, times(1)).onEnteredSafeMode(); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -795,7 +795,8 @@ public class VcnManagementServiceTest { false /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -807,7 +808,8 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, false /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test From 49f68bcfcc60fc59da17416df9d80e1ff00d7a92 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Feb 2021 13:16:04 -0800 Subject: [PATCH 0088/1057] Support converting IkeTrafficSelector to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(new tests added) Change-Id: I7b2613d62fa555c3c1eb125a1d971771b954e9ca --- .../IkeTrafficSelectorUtils.java | 74 +++++++++++++++++++ .../IkeTrafficSelectorUtilsTest.java | 66 +++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java new file mode 100644 index 0000000000..6bbc6b1e82 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java @@ -0,0 +1,74 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + +/** + * Provides utility methods to convert IkeTrafficSelector to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeTrafficSelectorUtils { + private static final String START_PORT_KEY = "START_PORT_KEY"; + private static final String END_PORT_KEY = "END_PORT_KEY"; + private static final String START_ADDRESS_KEY = "START_ADDRESS_KEY"; + private static final String END_ADDRESS_KEY = "END_ADDRESS_KEY"; + + /** Constructs an IkeTrafficSelector by deserializing a PersistableBundle. */ + @NonNull + public static IkeTrafficSelector fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final int startPort = in.getInt(START_PORT_KEY); + final int endPort = in.getInt(END_PORT_KEY); + + final String startingAddress = in.getString(START_ADDRESS_KEY); + final String endingAddress = in.getString(END_ADDRESS_KEY); + Objects.requireNonNull(startingAddress, "startAddress was null"); + Objects.requireNonNull(startingAddress, "endAddress was null"); + + return new IkeTrafficSelector( + startPort, + endPort, + InetAddresses.parseNumericAddress(startingAddress), + InetAddresses.parseNumericAddress(endingAddress)); + } + + /** Serializes an IkeTrafficSelector to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull IkeTrafficSelector ts) { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(START_PORT_KEY, ts.startPort); + result.putInt(END_PORT_KEY, ts.endPort); + result.putString(START_ADDRESS_KEY, ts.startingAddress.getHostAddress()); + result.putString(END_ADDRESS_KEY, ts.endingAddress.getHostAddress()); + + return result; + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java new file mode 100644 index 0000000000..28cf38a2a5 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java @@ -0,0 +1,66 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IkeTrafficSelectorUtilsTest { + private static final int START_PORT = 16; + private static final int END_PORT = 65520; + + private static final InetAddress IPV4_START_ADDRESS = + InetAddresses.parseNumericAddress("192.0.2.100"); + private static final InetAddress IPV4_END_ADDRESS = + InetAddresses.parseNumericAddress("192.0.2.101"); + + private static final InetAddress IPV6_START_ADDRESS = + InetAddresses.parseNumericAddress("2001:db8:2::100"); + private static final InetAddress IPV6_END_ADDRESS = + InetAddresses.parseNumericAddress("2001:db8:2::101"); + + private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeTrafficSelector ts) { + final PersistableBundle bundle = IkeTrafficSelectorUtils.toPersistableBundle(ts); + final IkeTrafficSelector resultTs = IkeTrafficSelectorUtils.fromPersistableBundle(bundle); + assertEquals(ts, resultTs); + } + + @Test + public void testPersistableBundleEncodeDecodeIsLosslessIpv4Ts() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeTrafficSelector(START_PORT, END_PORT, IPV4_START_ADDRESS, IPV4_END_ADDRESS)); + } + + @Test + public void testPersistableBundleEncodeDecodeIsLosslessIpv6Ts() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeTrafficSelector(START_PORT, END_PORT, IPV6_START_ADDRESS, IPV6_END_ADDRESS)); + } +} From 0da606ab5b7b2c19fdb92eebebeb953ef1d808a5 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Tue, 23 Feb 2021 18:55:26 -0800 Subject: [PATCH 0089/1057] [LSC] Add LOCAL_LICENSE_KINDS to cts Added SPDX-license-identifier-Apache-2.0 to: apps/CrossProfileTestApp/Android.bp apps/CtsVerifier/jni/audio_loopback/Android.bp apps/CtsVerifier/jni/megaaudio/Android.bp apps/CtsVerifier/jni/midi/Android.bp apps/CtsVerifier/jni/verifier/Android.bp apps/CtsVerifierInstantApp/Android.bp apps/CtsVerifierUSBCompanion/Android.bp apps/EmptyDeviceAdmin/Android.bp apps/EmptyDeviceOwner/Android.bp apps/ForceStopHelperApp/Android.bp apps/NotificationBot/Android.bp apps/OomCatcher/Android.bp apps/PermissionApp/Android.bp apps/TtsTestApp/Android.bp apps/VpnApp/Android.bp common/device-side/bedstead/activitycontext/Android.bp common/device-side/bedstead/dpmwrapper/Android.bp common/device-side/bedstead/eventlib/Android.bp common/device-side/bedstead/eventlib/src/test/testapp/Android.bp common/device-side/bedstead/harrier/Android.bp common/device-side/bedstead/nene/Android.bp common/device-side/bedstead/testapp/Android.bp common/device-side/device-info/Android.bp common/device-side/device-info/tests/Android.bp common/device-side/nativetesthelper/Android.bp common/device-side/nativetesthelper/jni/Android.bp common/device-side/preconditions/Android.bp common/device-side/test-app/Android.bp common/device-side/util-axt/Android.bp common/device-side/util-axt/tests/Android.bp common/device-side/util/jni/Android.bp common/host-side/util-axt/Android.bp helpers/default/Android.bp hostsidetests/abioverride/Android.bp hostsidetests/abioverride/app/Android.bp hostsidetests/abioverride/app/jni/Android.bp hostsidetests/accounts/Android.bp hostsidetests/accounts/test-apps/AccountManagerCrossUserApp/Android.bp hostsidetests/adb/Android.mk hostsidetests/adbmanager/Android.bp hostsidetests/angle/Android.bp hostsidetests/angle/app/common/Android.bp hostsidetests/angle/app/driverTest/Android.bp hostsidetests/angle/app/driverTestSecondary/Android.bp hostsidetests/apex/Android.bp hostsidetests/appbinding/app/Android.bp hostsidetests/appbinding/hostside/Android.bp hostsidetests/appcompat/compatchanges/Android.bp hostsidetests/appcompat/compatchanges/app/Android.bp hostsidetests/appcompat/compatchanges/preInstallOverrideApps/Android.bp hostsidetests/appcompat/compatchanges/selinuxapp/Android.bp hostsidetests/appcompat/hiddenapi/Android.bp hostsidetests/appcompat/hiddenapi/app/Android.bp hostsidetests/appcompat/host/lib/Android.bp hostsidetests/appcompat/strictjavapackages/Android.bp hostsidetests/appenumeration/Android.bp hostsidetests/appsecurity/Android.bp hostsidetests/appsecurity/certs/Android.bp hostsidetests/appsecurity/certs/keysets/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/testdata/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestAppPrebuilt/Android.bp hostsidetests/appsecurity/test-apps/AppAccessData/Android.bp hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppWithData/Android.bp hostsidetests/appsecurity/test-apps/ApplicationVisibilityCrossUserApp/Android.bp hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/compressed_arsc/Android.bp hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp hostsidetests/appsecurity/test-apps/DeviceIdentifiers/Android.bp hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/EncryptionApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.bp hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.bp hostsidetests/appsecurity/test-apps/InstantUpgradeApp/Android.bp hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/native_split/Android.bp hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk hostsidetests/appsecurity/test-apps/ListeningPortsApp/Android.bp hostsidetests/appsecurity/test-apps/LocationPolicyApp/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000000000ffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version00000000ffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ff00000000/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ffffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/src-common/Android.bp hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.bp hostsidetests/appsecurity/test-apps/OrderedActivityApp/Android.bp hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/Android.bp hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk hostsidetests/appsecurity/test-apps/StatsdSecurityApp/Android.bp hostsidetests/appsecurity/test-apps/StorageApp/Android.bp hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.bp hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.bp hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailActivity/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailApplication/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailProvider/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailReceiver/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailService/Android.bp hostsidetests/appsecurity/test-apps/UseProcessSuccess/Android.bp hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.bp hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permUse/Android.bp hostsidetests/appsecurity/test-apps/keysets/testApp/Android.bp hostsidetests/appsecurity/test-apps/keysets/uA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.bp hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uNone/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAll/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAndroid/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayApp/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyProduct/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySignatureDifferent/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySystem/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyVendor/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayTarget/Android.bp hostsidetests/appsecurity/test-apps/stubime/Android.bp hostsidetests/atrace/Android.bp hostsidetests/atrace/AtraceTestApp/Android.bp hostsidetests/atrace/AtraceTestApp/jni/Android.bp hostsidetests/backup/AdbBackupApp/Android.bp hostsidetests/backup/Android.bp hostsidetests/backup/AutoRestoreApp/Android.bp hostsidetests/backup/BackupEligibility/Android.bp hostsidetests/backup/BackupEligibility/BackupAllowedApp/Android.bp hostsidetests/backup/BackupEligibility/BackupNotAllowedApp/Android.bp hostsidetests/backup/BackupEligibility/DebuggableApp/Android.bp hostsidetests/backup/BackupEligibility/NonDebuggableApp/Android.bp hostsidetests/backup/BackupTransportApp/Android.bp hostsidetests/backup/FullBackupOnly/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.bp hostsidetests/backup/KeyValueApp/Android.bp hostsidetests/backup/OtherSoundsSettingsApp/Android.bp hostsidetests/backup/PreservedSettingsApp/Android.bp hostsidetests/backup/ProfileFullBackupApp/Android.bp hostsidetests/backup/ProfileKeyValueApp/Android.bp hostsidetests/backup/ProfileSerialNumberApp/Android.bp hostsidetests/backup/RestoreAnyVersion/Android.bp hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreSessionTest/Android.bp hostsidetests/backup/SharedPreferencesRestoreApp/Android.bp hostsidetests/backup/SuccessNotificationApp/Android.bp hostsidetests/backup/SyncAdapterSettingsApp/Android.bp hostsidetests/backup/fullbackupapp/Android.bp hostsidetests/backup/includeexcludeapp/Android.bp hostsidetests/backup/restoresessionapp1/Android.bp hostsidetests/backup/restoresessionapp2/Android.bp hostsidetests/backup/restoresessionapp3/Android.bp hostsidetests/blobstore/Android.bp hostsidetests/bootstats/Android.bp hostsidetests/calllog/Android.bp hostsidetests/calllog/app/Android.bp hostsidetests/car/Android.bp hostsidetests/car/app/Android.bp hostsidetests/classloaders/splits/Android.bp hostsidetests/classloaders/splits/apps/Android.bp hostsidetests/classloaders/splits/apps/feature_a/Android.bp hostsidetests/classloaders/splits/apps/feature_b/Android.bp hostsidetests/classloaders/useslibrary/Android.bp hostsidetests/classloaders/useslibrary/app/Android.bp hostsidetests/compilation/Android.bp hostsidetests/compilation/app/Android.bp hostsidetests/content/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileApp/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileTestServiceApp/Android.bp hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp hostsidetests/cpptools/Android.bp hostsidetests/cpptools/test-apps/BasicApp/Android.bp hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp hostsidetests/deviceidle/Android.bp hostsidetests/devicepolicy/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp hostsidetests/devicepolicy/app/AccountManagement/Android.bp hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp hostsidetests/devicepolicy/app/Assistant/Android.bp hostsidetests/devicepolicy/app/AutofillApp/Android.bp hostsidetests/devicepolicy/app/CertInstaller/Android.bp hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp hostsidetests/devicepolicy/app/CustomizationApp/Android.bp hostsidetests/devicepolicy/app/DelegateApp/Android.bp hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp hostsidetests/devicepolicy/app/DeviceOwner/Android.bp hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp hostsidetests/devicepolicy/app/IntentReceiver/Android.bp hostsidetests/devicepolicy/app/IntentSender/Android.bp hostsidetests/devicepolicy/app/LauncherTests/Android.bp hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp hostsidetests/devicepolicy/app/ManagedProfile/Android.bp hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp hostsidetests/devicepolicy/app/NotificationSender/Android.bp hostsidetests/devicepolicy/app/PackageInstaller/Android.bp hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp hostsidetests/devicepolicy/app/PrintingApp/Android.bp hostsidetests/devicepolicy/app/ProfileOwner/Android.bp hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp hostsidetests/devicepolicy/app/SharingApps/Android.bp hostsidetests/devicepolicy/app/SimpleApp/Android.bp hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp hostsidetests/devicepolicy/app/SuspensionChecker/Android.bp hostsidetests/devicepolicy/app/TestApps/Android.bp hostsidetests/devicepolicy/app/TestIme/Android.bp hostsidetests/devicepolicy/app/TestLauncher/Android.bp hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp hostsidetests/devicepolicy/app/WidgetProvider/Android.bp hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp hostsidetests/devicepolicy/app/common/Android.bp hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp hostsidetests/dexmetadata/app/Android.bp hostsidetests/dexmetadata/app/SplitApp/Android.bp hostsidetests/dexmetadata/app/SplitApp/SplitAppFeatureA/Android.bp hostsidetests/dexmetadata/host/Android.bp hostsidetests/dumpsys/Android.bp hostsidetests/dumpsys/apps/FramestatsTestApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.bp hostsidetests/dumpsys/apps/storagedapp/Android.bp hostsidetests/edi/Android.bp hostsidetests/gputools/apps/Android.bp hostsidetests/graphics/framerateoverride/Android.bp hostsidetests/graphics/framerateoverride/app/Android.bp hostsidetests/graphics/gpuprofiling/Android.bp hostsidetests/graphics/gpuprofiling/app/Android.bp hostsidetests/harmfulappwarning/Android.bp hostsidetests/harmfulappwarning/sampleapp/Android.bp hostsidetests/harmfulappwarning/testapp/Android.bp hostsidetests/hdmicec/Android.bp hostsidetests/hdmicec/app/Android.bp hostsidetests/incident/Android.bp hostsidetests/incident/apps/batterystatsapp/Android.bp hostsidetests/incident/apps/boundwidgetapp/Android.bp hostsidetests/incident/apps/errorsapp/Android.bp hostsidetests/incident/apps/errorsapp/jni/Android.bp hostsidetests/incident/apps/graphicsstatsapp/Android.bp hostsidetests/incident/apps/notificationsapp/Android.bp hostsidetests/incident/apps/procstatsapp/Android.bp hostsidetests/incrementalinstall/Android.bp hostsidetests/incrementalinstall/app/Android.bp hostsidetests/incrementalinstall/app/dynamicasset/Android.bp hostsidetests/incrementalinstall/app/dynamiccode/Android.bp hostsidetests/incrementalinstall/app/nativelibcompressed/Android.bp hostsidetests/incrementalinstall/app/nativelibuncompressed/Android.bp hostsidetests/incrementalinstall/appvalidator/Android.bp hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/jni/Android.bp hostsidetests/incrementalinstall/common/Android.bp hostsidetests/inputmethodservice/common/Android.bp hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp hostsidetests/inputmethodservice/deviceside/ime1/Android.bp hostsidetests/inputmethodservice/deviceside/ime2/Android.bp hostsidetests/inputmethodservice/deviceside/lib/Android.bp hostsidetests/inputmethodservice/deviceside/provider/Android.bp hostsidetests/inputmethodservice/hostside/Android.bp hostsidetests/install/Android.bp hostsidetests/jdwpsecurity/Android.bp hostsidetests/jdwpsecurity/app/Android.bp hostsidetests/jdwptunnel/Android.bp hostsidetests/jdwptunnel/sampleapps/ddmsapp/Android.bp hostsidetests/jdwptunnel/sampleapps/debuggableapp/Android.bp hostsidetests/jdwptunnel/sampleapps/profileableapp/Android.bp hostsidetests/jvmti/allocation-tracking/Android.bp hostsidetests/jvmti/allocation-tracking/app/Android.bp hostsidetests/jvmti/attaching/Android.bp hostsidetests/jvmti/base/app/Android.bp hostsidetests/jvmti/base/host/Android.bp hostsidetests/jvmti/base/jni/Android.bp hostsidetests/jvmti/base/run-test-based-app/Android.bp hostsidetests/jvmti/redefining/Android.bp hostsidetests/jvmti/redefining/app/Android.bp hostsidetests/jvmti/run-tests/Android.bp hostsidetests/jvmti/run-tests/test-1900/Android.bp hostsidetests/jvmti/run-tests/test-1900/app/Android.bp hostsidetests/jvmti/run-tests/test-1901/Android.bp hostsidetests/jvmti/run-tests/test-1901/app/Android.bp hostsidetests/jvmti/run-tests/test-1902/Android.bp hostsidetests/jvmti/run-tests/test-1902/app/Android.bp hostsidetests/jvmti/run-tests/test-1903/Android.bp hostsidetests/jvmti/run-tests/test-1903/app/Android.bp hostsidetests/jvmti/run-tests/test-1904/Android.bp hostsidetests/jvmti/run-tests/test-1904/app/Android.bp hostsidetests/jvmti/run-tests/test-1906/Android.bp hostsidetests/jvmti/run-tests/test-1906/app/Android.bp hostsidetests/jvmti/run-tests/test-1907/Android.bp hostsidetests/jvmti/run-tests/test-1907/app/Android.bp hostsidetests/jvmti/run-tests/test-1908/Android.bp hostsidetests/jvmti/run-tests/test-1908/app/Android.bp hostsidetests/jvmti/run-tests/test-1909/Android.bp hostsidetests/jvmti/run-tests/test-1909/app/Android.bp hostsidetests/jvmti/run-tests/test-1910/Android.bp hostsidetests/jvmti/run-tests/test-1910/app/Android.bp hostsidetests/jvmti/run-tests/test-1911/Android.bp hostsidetests/jvmti/run-tests/test-1911/app/Android.bp hostsidetests/jvmti/run-tests/test-1912/Android.bp hostsidetests/jvmti/run-tests/test-1912/app/Android.bp hostsidetests/jvmti/run-tests/test-1913/Android.bp hostsidetests/jvmti/run-tests/test-1913/app/Android.bp hostsidetests/jvmti/run-tests/test-1914/Android.bp hostsidetests/jvmti/run-tests/test-1914/app/Android.bp hostsidetests/jvmti/run-tests/test-1915/Android.bp hostsidetests/jvmti/run-tests/test-1915/app/Android.bp hostsidetests/jvmti/run-tests/test-1916/Android.bp hostsidetests/jvmti/run-tests/test-1916/app/Android.bp hostsidetests/jvmti/run-tests/test-1917/Android.bp hostsidetests/jvmti/run-tests/test-1917/app/Android.bp hostsidetests/jvmti/run-tests/test-1920/Android.bp hostsidetests/jvmti/run-tests/test-1920/app/Android.bp hostsidetests/jvmti/run-tests/test-1921/Android.bp hostsidetests/jvmti/run-tests/test-1921/app/Android.bp hostsidetests/jvmti/run-tests/test-1922/Android.bp hostsidetests/jvmti/run-tests/test-1922/app/Android.bp hostsidetests/jvmti/run-tests/test-1923/Android.bp hostsidetests/jvmti/run-tests/test-1923/app/Android.bp hostsidetests/jvmti/run-tests/test-1924/Android.bp hostsidetests/jvmti/run-tests/test-1924/app/Android.bp hostsidetests/jvmti/run-tests/test-1925/Android.bp hostsidetests/jvmti/run-tests/test-1925/app/Android.bp hostsidetests/jvmti/run-tests/test-1926/Android.bp hostsidetests/jvmti/run-tests/test-1926/app/Android.bp hostsidetests/jvmti/run-tests/test-1927/Android.bp hostsidetests/jvmti/run-tests/test-1927/app/Android.bp hostsidetests/jvmti/run-tests/test-1928/Android.bp hostsidetests/jvmti/run-tests/test-1928/app/Android.bp hostsidetests/jvmti/run-tests/test-1930/Android.bp hostsidetests/jvmti/run-tests/test-1930/app/Android.bp hostsidetests/jvmti/run-tests/test-1931/Android.bp hostsidetests/jvmti/run-tests/test-1931/app/Android.bp hostsidetests/jvmti/run-tests/test-1932/Android.bp hostsidetests/jvmti/run-tests/test-1932/app/Android.bp hostsidetests/jvmti/run-tests/test-1933/Android.bp hostsidetests/jvmti/run-tests/test-1933/app/Android.bp hostsidetests/jvmti/run-tests/test-1934/Android.bp hostsidetests/jvmti/run-tests/test-1934/app/Android.bp hostsidetests/jvmti/run-tests/test-1936/Android.bp hostsidetests/jvmti/run-tests/test-1936/app/Android.bp hostsidetests/jvmti/run-tests/test-1937/Android.bp hostsidetests/jvmti/run-tests/test-1937/app/Android.bp hostsidetests/jvmti/run-tests/test-1939/Android.bp hostsidetests/jvmti/run-tests/test-1939/app/Android.bp hostsidetests/jvmti/run-tests/test-1941/Android.bp hostsidetests/jvmti/run-tests/test-1941/app/Android.bp hostsidetests/jvmti/run-tests/test-1942/Android.bp hostsidetests/jvmti/run-tests/test-1942/app/Android.bp hostsidetests/jvmti/run-tests/test-1943/Android.bp hostsidetests/jvmti/run-tests/test-1943/app/Android.bp hostsidetests/jvmti/run-tests/test-1953/Android.bp hostsidetests/jvmti/run-tests/test-1953/app/Android.bp hostsidetests/jvmti/run-tests/test-1958/Android.bp hostsidetests/jvmti/run-tests/test-1958/app/Android.bp hostsidetests/jvmti/run-tests/test-1962/Android.bp hostsidetests/jvmti/run-tests/test-1962/app/Android.bp hostsidetests/jvmti/run-tests/test-1967/Android.bp hostsidetests/jvmti/run-tests/test-1967/app/Android.bp hostsidetests/jvmti/run-tests/test-1968/Android.bp hostsidetests/jvmti/run-tests/test-1968/app/Android.bp hostsidetests/jvmti/run-tests/test-1969/Android.bp hostsidetests/jvmti/run-tests/test-1969/app/Android.bp hostsidetests/jvmti/run-tests/test-1970/Android.bp hostsidetests/jvmti/run-tests/test-1970/app/Android.bp hostsidetests/jvmti/run-tests/test-1971/Android.bp hostsidetests/jvmti/run-tests/test-1971/app/Android.bp hostsidetests/jvmti/run-tests/test-1974/Android.bp hostsidetests/jvmti/run-tests/test-1974/app/Android.bp hostsidetests/jvmti/run-tests/test-1975/Android.bp hostsidetests/jvmti/run-tests/test-1975/app/Android.bp hostsidetests/jvmti/run-tests/test-1976/Android.bp hostsidetests/jvmti/run-tests/test-1976/app/Android.bp hostsidetests/jvmti/run-tests/test-1977/Android.bp hostsidetests/jvmti/run-tests/test-1977/app/Android.bp hostsidetests/jvmti/run-tests/test-1978/Android.bp hostsidetests/jvmti/run-tests/test-1978/app/Android.bp hostsidetests/jvmti/run-tests/test-1979/Android.bp hostsidetests/jvmti/run-tests/test-1979/app/Android.bp hostsidetests/jvmti/run-tests/test-1981/Android.bp hostsidetests/jvmti/run-tests/test-1981/app/Android.bp hostsidetests/jvmti/run-tests/test-1982/Android.bp hostsidetests/jvmti/run-tests/test-1982/app/Android.bp hostsidetests/jvmti/run-tests/test-1983/Android.bp hostsidetests/jvmti/run-tests/test-1983/app/Android.bp hostsidetests/jvmti/run-tests/test-1984/Android.bp hostsidetests/jvmti/run-tests/test-1984/app/Android.bp hostsidetests/jvmti/run-tests/test-1988/Android.bp hostsidetests/jvmti/run-tests/test-1988/app/Android.bp hostsidetests/jvmti/run-tests/test-1989/Android.bp hostsidetests/jvmti/run-tests/test-1989/app/Android.bp hostsidetests/jvmti/run-tests/test-1990/Android.bp hostsidetests/jvmti/run-tests/test-1990/app/Android.bp hostsidetests/jvmti/run-tests/test-1991/Android.bp hostsidetests/jvmti/run-tests/test-1991/app/Android.bp hostsidetests/jvmti/run-tests/test-1992/Android.bp hostsidetests/jvmti/run-tests/test-1992/app/Android.bp hostsidetests/jvmti/run-tests/test-1994/Android.bp hostsidetests/jvmti/run-tests/test-1994/app/Android.bp hostsidetests/jvmti/run-tests/test-1995/Android.bp hostsidetests/jvmti/run-tests/test-1995/app/Android.bp hostsidetests/jvmti/run-tests/test-1996/Android.bp hostsidetests/jvmti/run-tests/test-1996/app/Android.bp hostsidetests/jvmti/run-tests/test-1997/Android.bp hostsidetests/jvmti/run-tests/test-1997/app/Android.bp hostsidetests/jvmti/run-tests/test-1998/Android.bp hostsidetests/jvmti/run-tests/test-1998/app/Android.bp hostsidetests/jvmti/run-tests/test-1999/Android.bp hostsidetests/jvmti/run-tests/test-1999/app/Android.bp hostsidetests/jvmti/run-tests/test-2001/Android.bp hostsidetests/jvmti/run-tests/test-2001/app/Android.bp hostsidetests/jvmti/run-tests/test-2002/Android.bp hostsidetests/jvmti/run-tests/test-2002/app/Android.bp hostsidetests/jvmti/run-tests/test-2003/Android.bp hostsidetests/jvmti/run-tests/test-2003/app/Android.bp hostsidetests/jvmti/run-tests/test-2004/Android.bp hostsidetests/jvmti/run-tests/test-2004/app/Android.bp hostsidetests/jvmti/run-tests/test-2005/Android.bp hostsidetests/jvmti/run-tests/test-2005/app/Android.bp hostsidetests/jvmti/run-tests/test-2006/Android.bp hostsidetests/jvmti/run-tests/test-2006/app/Android.bp hostsidetests/jvmti/run-tests/test-2007/Android.bp hostsidetests/jvmti/run-tests/test-2007/app/Android.bp hostsidetests/jvmti/run-tests/test-902/Android.bp hostsidetests/jvmti/run-tests/test-902/app/Android.bp hostsidetests/jvmti/run-tests/test-903/Android.bp hostsidetests/jvmti/run-tests/test-903/app/Android.bp hostsidetests/jvmti/run-tests/test-904/Android.bp hostsidetests/jvmti/run-tests/test-904/app/Android.bp hostsidetests/jvmti/run-tests/test-905/Android.bp hostsidetests/jvmti/run-tests/test-905/app/Android.bp hostsidetests/jvmti/run-tests/test-906/Android.bp hostsidetests/jvmti/run-tests/test-906/app/Android.bp hostsidetests/jvmti/run-tests/test-907/Android.bp hostsidetests/jvmti/run-tests/test-907/app/Android.bp hostsidetests/jvmti/run-tests/test-908/Android.bp hostsidetests/jvmti/run-tests/test-908/app/Android.bp hostsidetests/jvmti/run-tests/test-910/Android.bp hostsidetests/jvmti/run-tests/test-910/app/Android.bp hostsidetests/jvmti/run-tests/test-911/Android.bp hostsidetests/jvmti/run-tests/test-911/app/Android.bp hostsidetests/jvmti/run-tests/test-912/Android.bp hostsidetests/jvmti/run-tests/test-912/app/Android.bp hostsidetests/jvmti/run-tests/test-913/Android.bp hostsidetests/jvmti/run-tests/test-913/app/Android.bp hostsidetests/jvmti/run-tests/test-914/Android.bp hostsidetests/jvmti/run-tests/test-914/app/Android.bp hostsidetests/jvmti/run-tests/test-915/Android.bp hostsidetests/jvmti/run-tests/test-915/app/Android.bp hostsidetests/jvmti/run-tests/test-917/Android.bp hostsidetests/jvmti/run-tests/test-917/app/Android.bp hostsidetests/jvmti/run-tests/test-918/Android.bp hostsidetests/jvmti/run-tests/test-918/app/Android.bp hostsidetests/jvmti/run-tests/test-919/Android.bp hostsidetests/jvmti/run-tests/test-919/app/Android.bp hostsidetests/jvmti/run-tests/test-920/Android.bp hostsidetests/jvmti/run-tests/test-920/app/Android.bp hostsidetests/jvmti/run-tests/test-922/Android.bp hostsidetests/jvmti/run-tests/test-922/app/Android.bp hostsidetests/jvmti/run-tests/test-923/Android.bp hostsidetests/jvmti/run-tests/test-923/app/Android.bp hostsidetests/jvmti/run-tests/test-924/Android.bp hostsidetests/jvmti/run-tests/test-924/app/Android.bp hostsidetests/jvmti/run-tests/test-926/Android.bp hostsidetests/jvmti/run-tests/test-926/app/Android.bp hostsidetests/jvmti/run-tests/test-927/Android.bp hostsidetests/jvmti/run-tests/test-927/app/Android.bp hostsidetests/jvmti/run-tests/test-928/Android.bp hostsidetests/jvmti/run-tests/test-928/app/Android.bp hostsidetests/jvmti/run-tests/test-930/Android.bp hostsidetests/jvmti/run-tests/test-930/app/Android.bp hostsidetests/jvmti/run-tests/test-931/Android.bp hostsidetests/jvmti/run-tests/test-931/app/Android.bp hostsidetests/jvmti/run-tests/test-932/Android.bp hostsidetests/jvmti/run-tests/test-932/app/Android.bp hostsidetests/jvmti/run-tests/test-940/Android.bp hostsidetests/jvmti/run-tests/test-940/app/Android.bp hostsidetests/jvmti/run-tests/test-942/Android.bp hostsidetests/jvmti/run-tests/test-942/app/Android.bp hostsidetests/jvmti/run-tests/test-944/Android.bp hostsidetests/jvmti/run-tests/test-944/app/Android.bp hostsidetests/jvmti/run-tests/test-945/Android.bp hostsidetests/jvmti/run-tests/test-945/app/Android.bp hostsidetests/jvmti/run-tests/test-947/Android.bp hostsidetests/jvmti/run-tests/test-947/app/Android.bp hostsidetests/jvmti/run-tests/test-951/Android.bp hostsidetests/jvmti/run-tests/test-951/app/Android.bp hostsidetests/jvmti/run-tests/test-982/Android.bp hostsidetests/jvmti/run-tests/test-982/app/Android.bp hostsidetests/jvmti/run-tests/test-983/Android.bp hostsidetests/jvmti/run-tests/test-983/app/Android.bp hostsidetests/jvmti/run-tests/test-984/Android.bp hostsidetests/jvmti/run-tests/test-984/app/Android.bp hostsidetests/jvmti/run-tests/test-985/Android.bp hostsidetests/jvmti/run-tests/test-985/app/Android.bp hostsidetests/jvmti/run-tests/test-986/Android.bp hostsidetests/jvmti/run-tests/test-986/app/Android.bp hostsidetests/jvmti/run-tests/test-988/Android.bp hostsidetests/jvmti/run-tests/test-988/app/Android.bp hostsidetests/jvmti/run-tests/test-989/Android.bp hostsidetests/jvmti/run-tests/test-989/app/Android.bp hostsidetests/jvmti/run-tests/test-990/Android.bp hostsidetests/jvmti/run-tests/test-990/app/Android.bp hostsidetests/jvmti/run-tests/test-991/Android.bp hostsidetests/jvmti/run-tests/test-991/app/Android.bp hostsidetests/jvmti/run-tests/test-992/Android.bp hostsidetests/jvmti/run-tests/test-992/app/Android.bp hostsidetests/jvmti/run-tests/test-993/Android.bp hostsidetests/jvmti/run-tests/test-993/app/Android.bp hostsidetests/jvmti/run-tests/test-994/Android.bp hostsidetests/jvmti/run-tests/test-994/app/Android.bp hostsidetests/jvmti/run-tests/test-995/Android.bp hostsidetests/jvmti/run-tests/test-995/app/Android.bp hostsidetests/jvmti/run-tests/test-996/Android.bp hostsidetests/jvmti/run-tests/test-996/app/Android.bp hostsidetests/jvmti/run-tests/test-997/Android.bp hostsidetests/jvmti/run-tests/test-997/app/Android.bp hostsidetests/jvmti/tagging/Android.bp hostsidetests/jvmti/tagging/app/Android.bp hostsidetests/library/Android.bp hostsidetests/media/Android.bp hostsidetests/media/app/MediaExtractorTest/Android.bp hostsidetests/media/app/MediaMetricsTest/Android.bp hostsidetests/media/app/MediaSessionTest/Android.bp hostsidetests/media/app/MediaSessionTestHelper/Android.bp hostsidetests/media/bitstreams/Android.bp hostsidetests/media/bitstreams/app/Android.bp hostsidetests/media/bitstreams/common/Android.bp hostsidetests/mediaparser/Android.bp hostsidetests/monkey/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.bp hostsidetests/multiuser/Android.bp hostsidetests/numberblocking/Android.bp hostsidetests/numberblocking/app/Android.bp hostsidetests/os/Android.bp hostsidetests/os/app/Android.bp hostsidetests/os/test-apps/EnvironmentTestApp/Android.bp hostsidetests/os/test-apps/HostLinkVerificationApp/Android.bp hostsidetests/os/test-apps/InattentiveSleepTestApp/Android.bp hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp hostsidetests/os/test-apps/ProcfsTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.bp hostsidetests/os/test-apps/StaticSharedLibTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.bp hostsidetests/packagemanager/codepath/Android.bp hostsidetests/packagemanager/codepath/app/Android.bp hostsidetests/packagemanager/dynamicmime/Android.bp hostsidetests/packagemanager/dynamicmime/app/Android.bp hostsidetests/packagemanager/dynamicmime/common/Android.bp hostsidetests/packagemanager/dynamicmime/test/Android.bp hostsidetests/packagemanager/extractnativelibs/Android.bp hostsidetests/packagemanager/extractnativelibs/apps/Android.bp hostsidetests/packagemanager/installedloadingprogess/deviceside/Android.bp hostsidetests/packagemanager/installedloadingprogess/hostside/Android.bp hostsidetests/packagemanager/installedloadingprogess/testdata/Android.bp hostsidetests/packagemanager/multiuser/Android.bp hostsidetests/packagemanager/multiuser/app/Android.bp hostsidetests/packagemanager/preferredactivity/Android.bp hostsidetests/packagemanager/preferredactivity/apps/testapp/Android.bp hostsidetests/packagemanager/stats/Android.bp hostsidetests/packagemanager/stats/apps/emptyapp/Android.bp hostsidetests/rollback/Android.bp hostsidetests/sample/Android.bp hostsidetests/sample/app/Android.bp hostsidetests/sample/app2/Android.bp hostsidetests/scopedstorage/Android.bp hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp hostsidetests/seccomp/Android.bp hostsidetests/seccomp/app/Android.bp hostsidetests/seccomp/app/jni/Android.bp hostsidetests/security/Android.mk hostsidetests/securitybulletin/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-137878930/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2182/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-4658/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5131/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0814/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0840/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13194/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13241/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13253/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9472/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9491/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9584/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9585/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2011/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2013/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2019/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2044/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2099/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2115/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2136/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2207/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9347/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0006/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0069/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0226/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0318/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/Android.bp hostsidetests/securitybulletin/securityPatch/includes/Android.bp hostsidetests/securitybulletin/test-apps/CVE-2021-0305/Android.bp hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp hostsidetests/settings/Android.bp hostsidetests/settings/app/DeviceOwnerApp/Android.bp hostsidetests/shortcuts/deviceside/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher1/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher2/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher3/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher1/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher2/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher3/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nobackup/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_wrongkey/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/common/Android.bp hostsidetests/shortcuts/deviceside/multiuser/Android.bp hostsidetests/shortcuts/deviceside/upgrade/Android.bp hostsidetests/shortcuts/hostside/Android.bp hostsidetests/signedconfig/app/Android.bp hostsidetests/signedconfig/hostside/Android.bp hostsidetests/stagedinstall/Android.bp hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/Android.bp hostsidetests/statsdatom/Android.bp hostsidetests/statsdatom/apps/statsdapp/Android.bp hostsidetests/sustainedperf/shadertoy_android/jni/Android.bp hostsidetests/systemui/Android.bp hostsidetests/systemui/app/Android.bp hostsidetests/tagging/Android.bp hostsidetests/tagging/common/Android.bp hostsidetests/tagging/manifest_disabled/Android.bp hostsidetests/tagging/manifest_enabled_sdk_29/Android.bp hostsidetests/tagging/manifest_enabled_sdk_30/Android.bp hostsidetests/tagging/sdk_29/Android.bp hostsidetests/tagging/sdk_30/Android.bp hostsidetests/telephony/Android.bp hostsidetests/telephony/devicetest/Android.bp hostsidetests/telephonyprovider/Android.bp hostsidetests/telephonyprovider/devicetest/Android.bp hostsidetests/testharness/Android.bp hostsidetests/testharness/app/Android.bp hostsidetests/theme/Android.mk hostsidetests/theme/app/Android.bp hostsidetests/time/Android.bp hostsidetests/trustedvoice/Android.bp hostsidetests/trustedvoice/app/Android.bp hostsidetests/tv/Android.bp hostsidetests/tv/app/Android.bp hostsidetests/tv/app2/Android.bp hostsidetests/tzdata/Android.bp hostsidetests/ui/Android.mk hostsidetests/ui/appA/Android.bp hostsidetests/ui/appB/Android.bp hostsidetests/ui/control/Android.bp hostsidetests/usage/Android.bp hostsidetests/usage/app/Android.bp hostsidetests/usb/Android.bp hostsidetests/usb/SerialTestApp/Android.bp hostsidetests/userspacereboot/Android.bp hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp hostsidetests/utils/Android.bp hostsidetests/webkit/Android.bp hostsidetests/webkit/app/Android.bp hostsidetests/wifibroadcasts/Android.bp hostsidetests/wifibroadcasts/app/Android.bp libs/deviceutillegacy/Android.bp libs/helpers/core/Android.bp libs/helpers/core/tests/Android.bp libs/helpers/interfaces/Android.bp libs/input/Android.bp libs/install/Android.bp libs/install/testapp/signing/Android.bp libs/json/Android.bp libs/midi/Android.bp libs/rollback/Android.bp libs/runner/Android.bp libs/shim/Android.bp libs/view/Android.bp libs/vogar-expect/Android.bp suite/audio_quality/executable/Android.bp suite/audio_quality/lib/Android.bp suite/audio_quality/test/Android.bp tests/AlarmManager/Android.bp tests/AlarmManager/app/Android.bp tests/BlobStore/Android.bp tests/BlobStore/certs/Android.bp tests/DropBoxManager/Android.bp tests/JobScheduler/Android.bp tests/JobScheduler/JobTestApp/Android.bp tests/JobSchedulerSharedUid/Android.bp tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp tests/JobSchedulerSharedUid/jobperm/Android.bp tests/JobSchedulerSharedUid/shareduid/Android.bp tests/ProcessTest/Android.bp tests/ProcessTest/NoShareUidApp/Android.bp tests/ProcessTest/ShareUidApp/Android.bp tests/acceleration/Android.bp tests/accessibility/Android.bp tests/accessibilityservice/Android.bp tests/accessibilityservice/test-apps/WidgetProvider/Android.bp tests/accessibilityservice/testsdk29/Android.bp tests/admin/Android.bp tests/admin/app/Android.bp tests/app/ActivityManagerApi29Test/Android.bp tests/app/Android.bp tests/app/BadProviderStubs/Android.bp tests/app/CantSaveState1/Android.bp tests/app/CantSaveState2/Android.bp tests/app/NotificationDelegator/Android.bp tests/app/NotificationListener/Android.bp tests/app/NotificationProvider/Android.bp tests/app/NotificationTrampoline/Android.bp tests/app/NotificationTrampolineApi30/Android.bp tests/app/NotificationTrampolineBase/Android.bp tests/app/StorageDelegator/Android.bp tests/app/app/Android.bp tests/app/shared/Android.bp tests/appintegrity/Android.bp tests/apppredictionservice/Android.bp tests/appsearch/Android.bp tests/appsearch/certs/Android.bp tests/aslr/Android.bp tests/attentionservice/Android.bp tests/autofillservice/Android.bp tests/autofillservice/TestAutofillService/Android.bp tests/backup/Android.bp tests/backup/app/Android.bp tests/bugreport/Android.bp tests/camera/Android.bp tests/camera/libctscamera2jni/Android.mk tests/camera/utils/Android.bp tests/contentcaptureservice/Android.bp tests/contentcaptureservice/OutsideOfPackageActivity/Android.bp tests/contentsuggestions/Android.bp tests/controls/Android.bp tests/core/runner-axt/Android.bp tests/devicepolicy/Android.bp tests/filesystem/Android.bp tests/fragment/Android.bp tests/fragment/sdk26/Android.bp tests/framework/base/biometrics/Android.bp tests/framework/base/biometrics/apps/biometrics/Android.bp tests/framework/base/biometrics/apps/fingerprint/Android.bp tests/framework/base/suggestions/Android.bp tests/framework/base/windowmanager/Android.bp tests/framework/base/windowmanager/alertwindowapp/Android.bp tests/framework/base/windowmanager/alertwindowappsdk25/Android.bp tests/framework/base/windowmanager/alertwindowservice/Android.bp tests/framework/base/windowmanager/app/Android.bp tests/framework/base/windowmanager/app27/Android.bp tests/framework/base/windowmanager/appAShareUid/Android.bp tests/framework/base/windowmanager/appBShareUid/Android.bp tests/framework/base/windowmanager/appDeprecatedSdk/Android.bp tests/framework/base/windowmanager/appDisplaySize/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp tests/framework/base/windowmanager/appProfileable/Android.bp tests/framework/base/windowmanager/appSecondUid/Android.bp tests/framework/base/windowmanager/appThirdUid/Android.bp tests/framework/base/windowmanager/app_base/Android.bp tests/framework/base/windowmanager/backgroundactivity/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppA/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppB/Android.bp tests/framework/base/windowmanager/backgroundactivity/common/Android.bp tests/framework/base/windowmanager/dndsourceapp/Android.bp tests/framework/base/windowmanager/dndtargetapp/Android.bp tests/framework/base/windowmanager/dndtargetappsdk23/Android.bp tests/framework/base/windowmanager/jetpack/Android.bp tests/framework/base/windowmanager/overlayappbase/Android.bp tests/framework/base/windowmanager/shared/Android.bp tests/framework/base/windowmanager/testsdk25/Android.bp tests/framework/base/windowmanager/testsdk28/Android.bp tests/framework/base/windowmanager/testsdk29/Android.bp tests/framework/base/windowmanager/translucentapp/Android.bp tests/framework/base/windowmanager/translucentappsdk26/Android.bp tests/framework/base/windowmanager/util/Android.bp tests/input/Android.bp tests/inputmethod/Android.bp tests/inputmethod/mockime/Android.bp tests/inputmethod/mockspellchecker/Android.bp tests/inputmethod/testapp/Android.bp tests/jdwp/Android.bp tests/jdwp/runner/device-side/Android.bp tests/jdwp/runner/host-side/Android.bp tests/leanbackjank/Android.bp tests/leanbackjank/app/Android.bp tests/libcore/jsr166/Android.bp tests/libcore/luni/Android.bp tests/libcore/ojluni/Android.bp tests/libcore/okhttp/Android.bp tests/libcore/runner/Android.bp tests/libcore/wycheproof-bc/Android.bp tests/libcore/wycheproof/Android.bp tests/location/common/Android.bp tests/location/location_coarse/Android.bp tests/location/location_fine/Android.bp tests/location/location_gnss/Android.bp tests/location/location_none/Android.bp tests/location/location_privileged/Android.bp tests/media/Android.bp tests/media/jni/Android.bp tests/mocking/Android.bp tests/mocking/debuggable/Android.bp tests/mocking/extended/Android.bp tests/mocking/inline/Android.bp tests/musicrecognition/Android.bp tests/musicrecognition/OutsideOfPackageService/Android.bp tests/netlegacy22.permission/Android.bp tests/netsecpolicy/Android.bp tests/openglperf2/jni/Android.bp tests/pdf/Android.bp tests/providerui/Android.bp tests/quickaccesswallet/Android.bp tests/rollback/Android.bp tests/sample/Android.bp tests/searchui/Android.bp tests/security/Android.bp tests/sensor/Android.bp tests/sensor/sensorratepermission/Android.bp tests/sensor/sensorratepermission/DebuggableAPI31/Android.bp tests/sensor/sensorratepermission/DirectReportAPI30/Android.bp tests/sensor/sensorratepermission/DirectReportAPI31/Android.bp tests/sensor/sensorratepermission/EventConnectionAPI30/Android.bp tests/sensor/sensorratepermission/EventConnectionAPI31/Android.bp tests/sensor/sensorratepermission/EventConnectionResampling/Android.bp tests/sensor/sensorratepermission/EventConnectionResampling/app/Android.bp tests/sensor/sensorratepermission/ReturnedRateInfo/Android.bp tests/signature/Android.bp tests/signature/api-check/Android.bp tests/signature/api-check/android-test-base-28-api/Android.bp tests/signature/api-check/android-test-base-current-api/Android.bp tests/signature/api-check/android-test-mock-current-api/Android.bp tests/signature/api-check/android-test-runner-current-api/Android.bp tests/signature/api-check/apache-http-legacy-27-api/Android.bp tests/signature/api-check/apache-http-legacy-current-api/Android.bp tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp tests/signature/api-check/current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-27-api/Android.bp tests/signature/api-check/hidden-api-blocklist-28-api/Android.bp tests/signature/api-check/hidden-api-blocklist-current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-debug-class/Android.bp tests/signature/api-check/hidden-api-blocklist-test-api/Android.bp tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp tests/signature/api-check/hidden-api-killswitch-sdklist/Android.bp tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp tests/signature/api-check/shared-libs-api/Android.mk tests/signature/api-check/system-annotation/Android.bp tests/signature/api-check/system-api/Android.mk tests/signature/api/Android.bp tests/signature/api/Android.mk tests/signature/dex-checker/Android.bp tests/signature/intent-check/Android.bp tests/signature/lib/android/Android.bp tests/signature/lib/common/Android.bp tests/signature/tests/Android.bp tests/simplecpu/jni/Android.bp tests/suspendapps/Android.bp tests/suspendapps/permission/Android.bp tests/suspendapps/test-apps/SuspendTestApp/Android.bp tests/suspendapps/test-apps/TestDeviceAdmin/Android.bp tests/suspendapps/tests/Android.bp tests/tests/accounts/Android.bp tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.bp tests/tests/accounts/common/Android.bp tests/tests/animation/Android.bp tests/tests/apache-http/Android.bp tests/tests/app.usage/Android.bp tests/tests/app.usage/TestApp1/Android.bp tests/tests/app.usage/TestApp2/Android.bp tests/tests/app/Android.bp tests/tests/appcomponentfactory/Android.bp tests/tests/appenumeration/Android.bp tests/tests/appenumeration/app/source/Android.bp tests/tests/appenumeration/app/target/Android.bp tests/tests/appenumeration/lib/Android.bp tests/tests/appop/Android.bp tests/tests/appop/AppInBackground/Android.bp tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp tests/tests/appop/AppThatUsesAppOps/Android.bp tests/tests/appop/AppToBlame1/Android.bp tests/tests/appop/AppToBlame2/Android.bp tests/tests/appop/AppToCollect/Android.bp tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp tests/tests/appop/AppWithDuplicateAttribution/Android.bp tests/tests/appop/AppWithLongAttributionTag/Android.bp tests/tests/appop/AppWithTooManyAttributions/Android.bp tests/tests/appop/aidl/AppOpsForegroundControlService/Android.bp tests/tests/appop/aidl/AppOpsUserService/Android.bp tests/tests/appop/appopsTestUtilLib/Android.bp tests/tests/appop2/Android.bp tests/tests/appwidget/Android.bp tests/tests/appwidget/packages/launchermanifest/Android.bp tests/tests/appwidget/packages/widgetprovider/Android.bp tests/tests/assist/Android.bp tests/tests/assist/common/Android.bp tests/tests/assist/service/Android.bp tests/tests/assist/testapp/Android.bp tests/tests/background/Android.bp tests/tests/batterysaving/Android.bp tests/tests/batterysaving/apps/app_target_api_25/Android.bp tests/tests/batterysaving/apps/app_target_api_current/Android.bp tests/tests/batterysaving/common/Android.bp tests/tests/binder_ndk/Android.bp tests/tests/binder_ndk/libbinder_ndk_test/Android.bp tests/tests/bionic/Android.mk tests/tests/bionic_app/Android.bp tests/tests/bluetooth/Android.bp tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp tests/tests/calendarcommon/Android.bp tests/tests/calendarprovider/Android.bp tests/tests/car/Android.bp tests/tests/carrierapi/Android.bp tests/tests/classloaderfactory/Android.bp tests/tests/classloaderfactory/test-memcl/Android.bp tests/tests/classloaderfactory/test-pathcl/Android.bp tests/tests/colormode/Android.bp tests/tests/contactsprovider/Android.bp tests/tests/contactsprovider/gal/Android.bp tests/tests/contactsproviderwipe/Android.bp tests/tests/content/Android.bp tests/tests/content/BinderPermissionTestService/Android.bp tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.bp tests/tests/content/DirectBootUnawareTestApp/Android.bp tests/tests/content/HelloWorldApp/Android.bp tests/tests/content/PackagePropertyTestApp/Android.bp tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp tests/tests/content/SyncAccountAccessStubs/Android.bp tests/tests/content/app/Android.bp tests/tests/content/emptytestapp/Android.bp tests/tests/content/jni/Android.bp tests/tests/content/lib/accountaccess/Android.bp tests/tests/content/pm/SecureFrp/Android.bp tests/tests/cronet/Android.bp tests/tests/database/Android.bp tests/tests/database/apps/Android.bp tests/tests/deviceconfig/Android.bp tests/tests/display/Android.bp tests/tests/dpi/Android.bp tests/tests/dpi2/Android.bp tests/tests/dreams/Android.bp tests/tests/drm/Android.bp tests/tests/drm/jni/Android.bp tests/tests/drm/lib/Android.bp tests/tests/dynamic_linker/Android.bp tests/tests/effect/Android.bp tests/tests/externalservice/Android.bp tests/tests/externalservice/common/Android.bp tests/tests/externalservice/service/Android.bp tests/tests/gesture/Android.bp tests/tests/graphics/Android.bp tests/tests/graphics/jni/Android.bp tests/tests/gwp-asan/enabled/Android.bp tests/tests/hardware/Android.bp tests/tests/hardware/jni/Android.bp tests/tests/icu/Android.bp tests/tests/icu/icu4c_testapp/Android.bp tests/tests/identity/Android.bp tests/tests/instantapp/Android.bp tests/tests/jni/Android.bp tests/tests/jni/libjnicommon/Android.bp tests/tests/jni/libjnitest/Android.bp tests/tests/jvmti/attaching/Android.bp tests/tests/jvmti/attaching/jni/Android.bp tests/tests/keystore/Android.bp tests/tests/libcoreapievolution/Android.bp tests/tests/libcorefileio/Android.bp tests/tests/libcorelegacy22/Android.bp tests/tests/libnativehelper/Android.bp tests/tests/libnativehelper/jni/Android.bp tests/tests/libthermalndk/Android.bp tests/tests/libthermalndk/jni/Android.bp tests/tests/match_flags/Android.bp tests/tests/match_flags/app/a/Android.bp tests/tests/match_flags/app/b/Android.bp tests/tests/media/libaudiojni/Android.bp tests/tests/media/libimagereaderjni/Android.bp tests/tests/media/libndkaudio/Android.bp tests/tests/mediaparser/Android.bp tests/tests/mediastress/Android.bp tests/tests/mediastress/jni/Android.bp tests/tests/mediatranscoding/Android.bp tests/tests/midi/Android.bp tests/tests/mimemap/Android.bp tests/tests/multiuser/Android.bp tests/tests/nativehardware/Android.bp tests/tests/nativehardware/jni/Android.bp tests/tests/nativemedia/aaudio/jni/Android.mk tests/tests/nativemedia/mediametrics/Android.bp tests/tests/nativemedia/sl/Android.mk tests/tests/nativemedia/xa/Android.mk tests/tests/nativemidi/jni/Android.mk tests/tests/ndef/Android.bp tests/tests/netpermission/internetpermission/Android.bp tests/tests/netpermission/updatestatspermission/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-false/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-true/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.bp tests/tests/networksecurityconfig/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.bp tests/tests/neuralnetworks/Android.mk tests/tests/neuralnetworks/tflite_delegate/Android.mk tests/tests/nfc/Android.bp tests/tests/notificationlegacy/notificationlegacy20/Android.bp tests/tests/notificationlegacy/notificationlegacy27/Android.bp tests/tests/notificationlegacy/notificationlegacy28/Android.bp tests/tests/notificationlegacy/notificationlegacy29/Android.bp tests/tests/notificationlegacy/notificationlegacy30/Android.bp tests/tests/opengl/Android.bp tests/tests/opengl/libopengltest/Android.bp tests/tests/openglperf/Android.bp tests/tests/openglperf/jni/Android.bp tests/tests/os/Android.bp tests/tests/os/Android.mk tests/tests/os/AutoRevokeQApp/Android.bp tests/tests/os/AutoRevokeRApp/Android.bp tests/tests/os/AutoRevokeSApp/Android.bp tests/tests/os/CompanionTestApp/Android.bp tests/tests/os/jni/Android.bp tests/tests/packageinstaller/adminpackageinstaller/Android.bp tests/tests/packageinstaller/atomicinstall/Android.bp tests/tests/packageinstaller/install/Android.bp tests/tests/packageinstaller/install_appop_default/Android.bp tests/tests/packageinstaller/install_appop_denied/Android.bp tests/tests/packageinstaller/nopermission/Android.bp tests/tests/packageinstaller/nopermission25/Android.bp tests/tests/packageinstaller/tapjacking/Android.bp tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp tests/tests/packageinstaller/test-apps/emptytestapp/Android.bp tests/tests/packageinstaller/uninstall/Android.bp tests/tests/packagewatchdog/Android.bp tests/tests/permission/Android.bp tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionA/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp tests/tests/permission/AppThatDefinesPermissionA/Android.bp tests/tests/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp tests/tests/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp tests/tests/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp tests/tests/permission/AppThatRequestContactsPermission15/Android.bp tests/tests/permission/AppThatRequestContactsPermission16/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission22/Android.bp tests/tests/permission/AppThatRequestLocationPermission28/Android.bp tests/tests/permission/AppThatRequestLocationPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp tests/tests/permission/AppThatRequestOneTimePermission/Android.bp tests/tests/permission/AppThatRequestPermissionAandB/Android.bp tests/tests/permission/AppThatRequestPermissionAandC/Android.bp tests/tests/permission/AppThatRequestStoragePermission28/Android.bp tests/tests/permission/AppThatRequestStoragePermission29/Android.bp tests/tests/permission/AppThatRunsRationaleTests/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp tests/tests/permission/StorageEscalationApp28/Android.bp tests/tests/permission/StorageEscalationApp29Full/Android.bp tests/tests/permission/StorageEscalationApp29Scoped/Android.bp tests/tests/permission/jni/Android.bp tests/tests/permission/nativeTests/Android.bp tests/tests/permission/permissionTestUtilLib/Android.bp tests/tests/permission/sdk28/Android.bp tests/tests/permission/telephony/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp tests/tests/permission2/Android.bp tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp tests/tests/permission3/Android.bp tests/tests/permission3/PermissionPolicyApp25/Android.bp tests/tests/permission3/UsePermissionApp22/Android.bp tests/tests/permission3/UsePermissionApp22CalendarOnly/Android.bp tests/tests/permission3/UsePermissionApp22None/Android.bp tests/tests/permission3/UsePermissionApp23/Android.bp tests/tests/permission3/UsePermissionApp25/Android.bp tests/tests/permission3/UsePermissionApp26/Android.bp tests/tests/permission3/UsePermissionApp28/Android.bp tests/tests/permission3/UsePermissionApp29/Android.bp tests/tests/permission3/UsePermissionApp30/Android.bp tests/tests/permission3/UsePermissionApp30WithBackground/Android.bp tests/tests/permission3/UsePermissionAppLatest/Android.bp tests/tests/permission3/UsePermissionAppLatestNone/Android.bp tests/tests/permission3/UsePermissionAppWithOverlay/Android.bp tests/tests/permission4/Android.bp tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp tests/tests/preference/Android.bp tests/tests/print/Android.bp tests/tests/print/ExternalPrintService/Android.bp tests/tests/print/printTestUtilLib/Android.bp tests/tests/proto/Android.bp tests/tests/provider/Android.bp tests/tests/provider/app/GalleryTestApp/Android.bp tests/tests/provider/preconditions/Android.bp tests/tests/renderscript/libcoremathtestcpp/Android.bp tests/tests/resolverservice/Android.bp tests/tests/resourcesloader/Android.bp tests/tests/resourcesloader/resources/Android.bp tests/tests/role/Android.bp tests/tests/role/CtsRoleTestApp/Android.bp tests/tests/role/CtsRoleTestApp28/Android.bp tests/tests/rsblas/libbnnmdata/Android.bp tests/tests/rscpp/librscpptest/Android.mk tests/tests/sax/Android.bp tests/tests/secure_element/access_control/AccessControlApp1/Android.bp tests/tests/secure_element/access_control/AccessControlApp2/Android.bp tests/tests/secure_element/access_control/AccessControlApp3/Android.bp tests/tests/secure_element/omapi/Android.bp tests/tests/security/Android.bp tests/tests/security/jni/Android.bp tests/tests/security/native/encryption/Android.bp tests/tests/security/native/verified_boot/Android.bp tests/tests/security/testeffect/Android.bp tests/tests/selinux/common/jni/Android.bp tests/tests/selinux/selinuxEphemeral/Android.bp tests/tests/selinux/selinuxTargetSdk25/Android.bp tests/tests/selinux/selinuxTargetSdk27/Android.bp tests/tests/selinux/selinuxTargetSdk28/Android.bp tests/tests/selinux/selinuxTargetSdk29/Android.bp tests/tests/selinux/selinuxTargetSdkCurrent/Android.bp tests/tests/settings/Android.bp tests/tests/sharesheet/Android.bp tests/tests/sharesheet/packages/Android.bp tests/tests/shortcutmanager/Android.bp tests/tests/simphonebookprovider/Android.bp tests/tests/simphonebookprovider/nosim/Android.bp tests/tests/simpleperf/Android.mk tests/tests/simpleperf/CtsSimpleperfDebuggableApp/Android.bp tests/tests/simpleperf/CtsSimpleperfProfileableApp/Android.bp tests/tests/slice/Android.bp tests/tests/soundtrigger/Android.bp tests/tests/speech/Android.bp tests/tests/syncmanager/Android.bp tests/tests/syncmanager/apps/Android.bp tests/tests/syncmanager/common/Android.bp tests/tests/systemintents/Android.bp tests/tests/systemui/Android.bp tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp tests/tests/systemui/AudioRecorderTestApp_Base/Android.bp tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp tests/tests/systemui/PipTestApp/Android.bp tests/tests/systemui/common/Android.bp tests/tests/telecom/Android.bp tests/tests/telecom/Api29InCallServiceTestApp/Android.bp tests/tests/telecom/CallRedirectionServiceTestApp/Android.bp tests/tests/telecom/CallScreeningServiceTestApp/Android.bp tests/tests/telecom/CarModeTestApp/Android.bp tests/tests/telecom/CarModeTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyDialerTestApp/Android.bp tests/tests/telecom/ThirdPtyDialerTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyInCallServiceTestApp/Android.bp tests/tests/telecom2/Android.bp tests/tests/telecom3/Android.bp tests/tests/telephony/TestFinancialSmsApp/Android.bp tests/tests/telephony/TestSmsApp/Android.bp tests/tests/telephony/TestSmsApp22/Android.bp tests/tests/telephony/TestSmsRetrieverApp/Android.bp tests/tests/telephony/current/Android.bp tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp tests/tests/telephony/current/permissions/Android.bp tests/tests/telephony/current/preconditions/Android.bp tests/tests/telephony/current/preconditions/app/Android.bp tests/tests/telephony/current/src/android/telephony/cts/util/Android.bp tests/tests/telephony/sdk28/Android.bp tests/tests/telephony2/Android.bp tests/tests/telephony3/Android.bp tests/tests/telephony4/Android.bp tests/tests/telephony4/certs/Android.bp tests/tests/telephonyprovider/Android.bp tests/tests/text/Android.bp tests/tests/text/jni/Android.bp tests/tests/textclassifier/Android.bp tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp tests/tests/theme/Android.bp tests/tests/time/Android.bp tests/tests/toast/Android.bp tests/tests/toastlegacy/Android.bp tests/tests/tools/processors/view_inspector/Android.bp tests/tests/transition/Android.bp tests/tests/tv/Android.bp tests/tests/uiautomation/Android.bp tests/tests/uidisolation/Android.bp tests/tests/uirendering/Android.bp tests/tests/uirendering/jni/Android.bp tests/tests/uirendering27/Android.bp tests/tests/usb/Android.bp tests/tests/util/Android.bp tests/tests/vcn/Android.bp tests/tests/view/jni/Android.bp tests/tests/view/sdk28/Android.bp tests/tests/view/surfacevalidator/Android.bp tests/tests/voiceRecognition/Android.bp tests/tests/voiceRecognition/RecognitionService/Android.bp tests/tests/voiceinteraction/Android.bp tests/tests/voiceinteraction/common/Android.bp tests/tests/voiceinteraction/service/Android.bp tests/tests/voiceinteraction/testapp/Android.bp tests/tests/voicesettings/Android.bp tests/tests/voicesettings/service/Android.bp tests/tests/webkit/Android.bp tests/tests/widget/Android.bp tests/tests/widget/app/Android.bp tests/tests/widget29/Android.bp tests/tests/wifi/Android.bp tests/tests/wifi/CtsWifiLocationTestApp/Android.bp tests/translation/Android.bp tests/tvprovider/Android.bp tests/uwb/Android.bp tests/video/Android.bp tests/vr/Android.bp tests/vr/jni/Android.bp tools/cfassembler/Android.bp tools/cts-api-coverage/Android.bp tools/cts-device-info/jni/Android.bp tools/cts-dynamic-config/Android.mk tools/cts-holo-generation/Android.bp tools/cts-media-preparer-app/Android.bp tools/cts-preconditions/Android.bp tools/cts-tradefed/Android.bp tools/cts-tradefed/tests/Android.bp tools/device-setup/TestDeviceSetup/Android.bp tools/manifest-generator/Android.bp tools/manifest-generator/tests/Android.bp tools/release-parser/Android.bp tools/release-parser/tests/Android.bp tools/vm-tests-tf/Android.bp tools/vm-tests-tf/Android.mk tools/vm-tests-tf/targetprep/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/testserver/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY to: apps/CtsVerifier/Android.bp apps/CtsVerifier/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-MIT SPDX-license-identifier-NCSA legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CC-BY legacy_unencumbered to: tests/tests/media/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: hostsidetests/gputools/Android.bp hostsidetests/gputools/layers/Android.bp Added SPDX-license-identifier-Apache-2.0 legacy_unencumbered to: tests/tests/media/libmediandkjni/Android.bp Added SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/dhrystone/Android.mk Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Iceb1641ab8d94a4387136e3e7b6cda3d5cde857f --- Vcn/tests/cts/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 5666ee78a5..ecb1236b9b 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test { name: "CtsVcnTestCases", defaults: ["cts_defaults"], From e9384c6b3bdb8124a8bc54cf9aa5b6cb6b94adf8 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Tue, 23 Feb 2021 14:05:02 -0800 Subject: [PATCH 0090/1057] [LSC] Add LOCAL_LICENSE_KINDS to cts Added SPDX-license-identifier-Apache-2.0 to: apps/CrossProfileTestApp/Android.bp apps/CtsVerifier/jni/audio_loopback/Android.bp apps/CtsVerifier/jni/megaaudio/Android.bp apps/CtsVerifier/jni/midi/Android.bp apps/CtsVerifier/jni/verifier/Android.bp apps/CtsVerifierInstantApp/Android.bp apps/CtsVerifierUSBCompanion/Android.bp apps/EmptyDeviceAdmin/Android.bp apps/EmptyDeviceOwner/Android.bp apps/ForceStopHelperApp/Android.bp apps/NotificationBot/Android.bp apps/OomCatcher/Android.bp apps/PermissionApp/Android.bp apps/TtsTestApp/Android.bp apps/VpnApp/Android.bp common/device-side/bedstead/activitycontext/Android.bp common/device-side/bedstead/dpmwrapper/Android.bp common/device-side/bedstead/eventlib/Android.bp common/device-side/bedstead/eventlib/src/test/testapp/Android.bp common/device-side/bedstead/harrier/Android.bp common/device-side/bedstead/nene/Android.bp common/device-side/bedstead/testapp/Android.bp common/device-side/device-info/Android.bp common/device-side/device-info/tests/Android.bp common/device-side/nativetesthelper/Android.bp common/device-side/nativetesthelper/jni/Android.bp common/device-side/preconditions/Android.bp common/device-side/test-app/Android.bp common/device-side/util-axt/Android.bp common/device-side/util-axt/tests/Android.bp common/device-side/util/jni/Android.bp common/host-side/util-axt/Android.bp helpers/default/Android.bp hostsidetests/abioverride/Android.bp hostsidetests/abioverride/app/Android.bp hostsidetests/abioverride/app/jni/Android.bp hostsidetests/accounts/Android.bp hostsidetests/accounts/test-apps/AccountManagerCrossUserApp/Android.bp hostsidetests/adb/Android.mk hostsidetests/adbmanager/Android.bp hostsidetests/angle/Android.bp hostsidetests/angle/app/common/Android.bp hostsidetests/angle/app/driverTest/Android.bp hostsidetests/angle/app/driverTestSecondary/Android.bp hostsidetests/apex/Android.bp hostsidetests/appbinding/app/Android.bp hostsidetests/appbinding/hostside/Android.bp hostsidetests/appcompat/compatchanges/Android.bp hostsidetests/appcompat/compatchanges/app/Android.bp hostsidetests/appcompat/compatchanges/preInstallOverrideApps/Android.bp hostsidetests/appcompat/compatchanges/selinuxapp/Android.bp hostsidetests/appcompat/hiddenapi/Android.bp hostsidetests/appcompat/hiddenapi/app/Android.bp hostsidetests/appcompat/host/lib/Android.bp hostsidetests/appcompat/strictjavapackages/Android.bp hostsidetests/appenumeration/Android.bp hostsidetests/appsecurity/Android.bp hostsidetests/appsecurity/certs/Android.bp hostsidetests/appsecurity/certs/keysets/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.bp hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestApp/testdata/Android.bp hostsidetests/appsecurity/test-apps/ApkVerityTestAppPrebuilt/Android.bp hostsidetests/appsecurity/test-apps/AppAccessData/Android.bp hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp hostsidetests/appsecurity/test-apps/AppWithData/Android.bp hostsidetests/appsecurity/test-apps/ApplicationVisibilityCrossUserApp/Android.bp hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/Android.bp hostsidetests/appsecurity/test-apps/CorruptApkTests/compressed_arsc/Android.bp hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp hostsidetests/appsecurity/test-apps/DeviceIdentifiers/Android.bp hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/EncryptionApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.bp hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.bp hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.bp hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.bp hostsidetests/appsecurity/test-apps/InstantUpgradeApp/Android.bp hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.bp hostsidetests/appsecurity/test-apps/IsolatedSplitApp/native_split/Android.bp hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk hostsidetests/appsecurity/test-apps/ListeningPortsApp/Android.bp hostsidetests/appsecurity/test-apps/LocationPolicyApp/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000000000ffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version00000000ffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ff00000000/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/Version000000ffffffffff/Android.bp hostsidetests/appsecurity/test-apps/MajorVersionApp/src-common/Android.bp hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/Android.bp hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.bp hostsidetests/appsecurity/test-apps/OrderedActivityApp/Android.bp hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerPermissionRequestApp/Android.bp hostsidetests/appsecurity/test-apps/PackageInstallerWhitelistApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.bp hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/Android.bp hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.bp hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.bp hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.bp hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk hostsidetests/appsecurity/test-apps/StatsdSecurityApp/Android.bp hostsidetests/appsecurity/test-apps/StorageApp/Android.bp hostsidetests/appsecurity/test-apps/StorageStatsApp/Android.bp hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.bp hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailActivity/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailApplication/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailProvider/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailReceiver/Android.bp hostsidetests/appsecurity/test-apps/UseProcessFailService/Android.bp hostsidetests/appsecurity/test-apps/UseProcessSuccess/Android.bp hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.bp hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permDef/Android.bp hostsidetests/appsecurity/test-apps/keysets/permUse/Android.bp hostsidetests/appsecurity/test-apps/keysets/testApp/Android.bp hostsidetests/appsecurity/test-apps/keysets/uA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uB/Android.bp hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.bp hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.bp hostsidetests/appsecurity/test-apps/keysets/uNone/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAll/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayAndroid/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayApp/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyProduct/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySignatureDifferent/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicySystem/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayPolicyVendor/Android.bp hostsidetests/appsecurity/test-apps/rro/OverlayTarget/Android.bp hostsidetests/appsecurity/test-apps/stubime/Android.bp hostsidetests/atrace/Android.bp hostsidetests/atrace/AtraceTestApp/Android.bp hostsidetests/atrace/AtraceTestApp/jni/Android.bp hostsidetests/backup/AdbBackupApp/Android.bp hostsidetests/backup/Android.bp hostsidetests/backup/AutoRestoreApp/Android.bp hostsidetests/backup/BackupEligibility/Android.bp hostsidetests/backup/BackupEligibility/BackupAllowedApp/Android.bp hostsidetests/backup/BackupEligibility/BackupNotAllowedApp/Android.bp hostsidetests/backup/BackupEligibility/DebuggableApp/Android.bp hostsidetests/backup/BackupEligibility/NonDebuggableApp/Android.bp hostsidetests/backup/BackupTransportApp/Android.bp hostsidetests/backup/FullBackupOnly/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.bp hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.bp hostsidetests/backup/KeyValueApp/Android.bp hostsidetests/backup/OtherSoundsSettingsApp/Android.bp hostsidetests/backup/PreservedSettingsApp/Android.bp hostsidetests/backup/ProfileFullBackupApp/Android.bp hostsidetests/backup/ProfileKeyValueApp/Android.bp hostsidetests/backup/ProfileSerialNumberApp/Android.bp hostsidetests/backup/RestoreAnyVersion/Android.bp hostsidetests/backup/RestoreAnyVersion/NewVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/NoRestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreAnyVersion/RestoreAnyVersionApp/Android.bp hostsidetests/backup/RestoreSessionTest/Android.bp hostsidetests/backup/SharedPreferencesRestoreApp/Android.bp hostsidetests/backup/SuccessNotificationApp/Android.bp hostsidetests/backup/SyncAdapterSettingsApp/Android.bp hostsidetests/backup/fullbackupapp/Android.bp hostsidetests/backup/includeexcludeapp/Android.bp hostsidetests/backup/restoresessionapp1/Android.bp hostsidetests/backup/restoresessionapp2/Android.bp hostsidetests/backup/restoresessionapp3/Android.bp hostsidetests/blobstore/Android.bp hostsidetests/bootstats/Android.bp hostsidetests/calllog/Android.bp hostsidetests/calllog/app/Android.bp hostsidetests/car/Android.bp hostsidetests/car/app/Android.bp hostsidetests/classloaders/splits/Android.bp hostsidetests/classloaders/splits/apps/Android.bp hostsidetests/classloaders/splits/apps/feature_a/Android.bp hostsidetests/classloaders/splits/apps/feature_b/Android.bp hostsidetests/classloaders/useslibrary/Android.bp hostsidetests/classloaders/useslibrary/app/Android.bp hostsidetests/compilation/Android.bp hostsidetests/compilation/app/Android.bp hostsidetests/content/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileApp/Android.bp hostsidetests/content/test-apps/ContextCrossProfileApps/ContextCrossProfileTestServiceApp/Android.bp hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp hostsidetests/cpptools/Android.bp hostsidetests/cpptools/test-apps/BasicApp/Android.bp hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp hostsidetests/cpptools/test-apps/DomainSocketApp/Android.bp hostsidetests/deviceidle/Android.bp hostsidetests/devicepolicy/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp hostsidetests/devicepolicy/app/AccountManagement/Android.bp hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp hostsidetests/devicepolicy/app/Assistant/Android.bp hostsidetests/devicepolicy/app/AutofillApp/Android.bp hostsidetests/devicepolicy/app/CertInstaller/Android.bp hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp hostsidetests/devicepolicy/app/CustomizationApp/Android.bp hostsidetests/devicepolicy/app/DelegateApp/Android.bp hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp hostsidetests/devicepolicy/app/DeviceOwner/Android.bp hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp hostsidetests/devicepolicy/app/IntentReceiver/Android.bp hostsidetests/devicepolicy/app/IntentSender/Android.bp hostsidetests/devicepolicy/app/LauncherTests/Android.bp hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp hostsidetests/devicepolicy/app/ManagedProfile/Android.bp hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp hostsidetests/devicepolicy/app/NotificationSender/Android.bp hostsidetests/devicepolicy/app/PackageInstaller/Android.bp hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp hostsidetests/devicepolicy/app/PrintingApp/Android.bp hostsidetests/devicepolicy/app/ProfileOwner/Android.bp hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp hostsidetests/devicepolicy/app/SharingApps/Android.bp hostsidetests/devicepolicy/app/SimpleApp/Android.bp hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp hostsidetests/devicepolicy/app/SuspensionChecker/Android.bp hostsidetests/devicepolicy/app/TestApps/Android.bp hostsidetests/devicepolicy/app/TestIme/Android.bp hostsidetests/devicepolicy/app/TestLauncher/Android.bp hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp hostsidetests/devicepolicy/app/WidgetProvider/Android.bp hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp hostsidetests/devicepolicy/app/common/Android.bp hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp hostsidetests/dexmetadata/app/Android.bp hostsidetests/dexmetadata/app/SplitApp/Android.bp hostsidetests/dexmetadata/app/SplitApp/SplitAppFeatureA/Android.bp hostsidetests/dexmetadata/host/Android.bp hostsidetests/dumpsys/Android.bp hostsidetests/dumpsys/apps/FramestatsTestApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsHelperApp/Android.bp hostsidetests/dumpsys/apps/ProcStatsTestApp/Android.bp hostsidetests/dumpsys/apps/storagedapp/Android.bp hostsidetests/edi/Android.bp hostsidetests/gputools/apps/Android.bp hostsidetests/graphics/framerateoverride/Android.bp hostsidetests/graphics/framerateoverride/app/Android.bp hostsidetests/graphics/gpuprofiling/Android.bp hostsidetests/graphics/gpuprofiling/app/Android.bp hostsidetests/harmfulappwarning/Android.bp hostsidetests/harmfulappwarning/sampleapp/Android.bp hostsidetests/harmfulappwarning/testapp/Android.bp hostsidetests/hdmicec/Android.bp hostsidetests/hdmicec/app/Android.bp hostsidetests/incident/Android.bp hostsidetests/incident/apps/batterystatsapp/Android.bp hostsidetests/incident/apps/boundwidgetapp/Android.bp hostsidetests/incident/apps/errorsapp/Android.bp hostsidetests/incident/apps/errorsapp/jni/Android.bp hostsidetests/incident/apps/graphicsstatsapp/Android.bp hostsidetests/incident/apps/notificationsapp/Android.bp hostsidetests/incident/apps/procstatsapp/Android.bp hostsidetests/incrementalinstall/Android.bp hostsidetests/incrementalinstall/app/Android.bp hostsidetests/incrementalinstall/app/dynamicasset/Android.bp hostsidetests/incrementalinstall/app/dynamiccode/Android.bp hostsidetests/incrementalinstall/app/nativelibcompressed/Android.bp hostsidetests/incrementalinstall/app/nativelibuncompressed/Android.bp hostsidetests/incrementalinstall/appvalidator/Android.bp hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/jni/Android.bp hostsidetests/incrementalinstall/common/Android.bp hostsidetests/inputmethodservice/common/Android.bp hostsidetests/inputmethodservice/deviceside/devicetest/Android.bp hostsidetests/inputmethodservice/deviceside/edittextapp/Android.bp hostsidetests/inputmethodservice/deviceside/ime1/Android.bp hostsidetests/inputmethodservice/deviceside/ime2/Android.bp hostsidetests/inputmethodservice/deviceside/lib/Android.bp hostsidetests/inputmethodservice/deviceside/provider/Android.bp hostsidetests/inputmethodservice/hostside/Android.bp hostsidetests/install/Android.bp hostsidetests/jdwpsecurity/Android.bp hostsidetests/jdwpsecurity/app/Android.bp hostsidetests/jdwptunnel/Android.bp hostsidetests/jdwptunnel/sampleapps/ddmsapp/Android.bp hostsidetests/jdwptunnel/sampleapps/debuggableapp/Android.bp hostsidetests/jdwptunnel/sampleapps/profileableapp/Android.bp hostsidetests/jvmti/allocation-tracking/Android.bp hostsidetests/jvmti/allocation-tracking/app/Android.bp hostsidetests/jvmti/attaching/Android.bp hostsidetests/jvmti/base/app/Android.bp hostsidetests/jvmti/base/host/Android.bp hostsidetests/jvmti/base/jni/Android.bp hostsidetests/jvmti/base/run-test-based-app/Android.bp hostsidetests/jvmti/redefining/Android.bp hostsidetests/jvmti/redefining/app/Android.bp hostsidetests/jvmti/run-tests/Android.bp hostsidetests/jvmti/run-tests/test-1900/Android.bp hostsidetests/jvmti/run-tests/test-1900/app/Android.bp hostsidetests/jvmti/run-tests/test-1901/Android.bp hostsidetests/jvmti/run-tests/test-1901/app/Android.bp hostsidetests/jvmti/run-tests/test-1902/Android.bp hostsidetests/jvmti/run-tests/test-1902/app/Android.bp hostsidetests/jvmti/run-tests/test-1903/Android.bp hostsidetests/jvmti/run-tests/test-1903/app/Android.bp hostsidetests/jvmti/run-tests/test-1904/Android.bp hostsidetests/jvmti/run-tests/test-1904/app/Android.bp hostsidetests/jvmti/run-tests/test-1906/Android.bp hostsidetests/jvmti/run-tests/test-1906/app/Android.bp hostsidetests/jvmti/run-tests/test-1907/Android.bp hostsidetests/jvmti/run-tests/test-1907/app/Android.bp hostsidetests/jvmti/run-tests/test-1908/Android.bp hostsidetests/jvmti/run-tests/test-1908/app/Android.bp hostsidetests/jvmti/run-tests/test-1909/Android.bp hostsidetests/jvmti/run-tests/test-1909/app/Android.bp hostsidetests/jvmti/run-tests/test-1910/Android.bp hostsidetests/jvmti/run-tests/test-1910/app/Android.bp hostsidetests/jvmti/run-tests/test-1911/Android.bp hostsidetests/jvmti/run-tests/test-1911/app/Android.bp hostsidetests/jvmti/run-tests/test-1912/Android.bp hostsidetests/jvmti/run-tests/test-1912/app/Android.bp hostsidetests/jvmti/run-tests/test-1913/Android.bp hostsidetests/jvmti/run-tests/test-1913/app/Android.bp hostsidetests/jvmti/run-tests/test-1914/Android.bp hostsidetests/jvmti/run-tests/test-1914/app/Android.bp hostsidetests/jvmti/run-tests/test-1915/Android.bp hostsidetests/jvmti/run-tests/test-1915/app/Android.bp hostsidetests/jvmti/run-tests/test-1916/Android.bp hostsidetests/jvmti/run-tests/test-1916/app/Android.bp hostsidetests/jvmti/run-tests/test-1917/Android.bp hostsidetests/jvmti/run-tests/test-1917/app/Android.bp hostsidetests/jvmti/run-tests/test-1920/Android.bp hostsidetests/jvmti/run-tests/test-1920/app/Android.bp hostsidetests/jvmti/run-tests/test-1921/Android.bp hostsidetests/jvmti/run-tests/test-1921/app/Android.bp hostsidetests/jvmti/run-tests/test-1922/Android.bp hostsidetests/jvmti/run-tests/test-1922/app/Android.bp hostsidetests/jvmti/run-tests/test-1923/Android.bp hostsidetests/jvmti/run-tests/test-1923/app/Android.bp hostsidetests/jvmti/run-tests/test-1924/Android.bp hostsidetests/jvmti/run-tests/test-1924/app/Android.bp hostsidetests/jvmti/run-tests/test-1925/Android.bp hostsidetests/jvmti/run-tests/test-1925/app/Android.bp hostsidetests/jvmti/run-tests/test-1926/Android.bp hostsidetests/jvmti/run-tests/test-1926/app/Android.bp hostsidetests/jvmti/run-tests/test-1927/Android.bp hostsidetests/jvmti/run-tests/test-1927/app/Android.bp hostsidetests/jvmti/run-tests/test-1928/Android.bp hostsidetests/jvmti/run-tests/test-1928/app/Android.bp hostsidetests/jvmti/run-tests/test-1930/Android.bp hostsidetests/jvmti/run-tests/test-1930/app/Android.bp hostsidetests/jvmti/run-tests/test-1931/Android.bp hostsidetests/jvmti/run-tests/test-1931/app/Android.bp hostsidetests/jvmti/run-tests/test-1932/Android.bp hostsidetests/jvmti/run-tests/test-1932/app/Android.bp hostsidetests/jvmti/run-tests/test-1933/Android.bp hostsidetests/jvmti/run-tests/test-1933/app/Android.bp hostsidetests/jvmti/run-tests/test-1934/Android.bp hostsidetests/jvmti/run-tests/test-1934/app/Android.bp hostsidetests/jvmti/run-tests/test-1936/Android.bp hostsidetests/jvmti/run-tests/test-1936/app/Android.bp hostsidetests/jvmti/run-tests/test-1937/Android.bp hostsidetests/jvmti/run-tests/test-1937/app/Android.bp hostsidetests/jvmti/run-tests/test-1939/Android.bp hostsidetests/jvmti/run-tests/test-1939/app/Android.bp hostsidetests/jvmti/run-tests/test-1941/Android.bp hostsidetests/jvmti/run-tests/test-1941/app/Android.bp hostsidetests/jvmti/run-tests/test-1942/Android.bp hostsidetests/jvmti/run-tests/test-1942/app/Android.bp hostsidetests/jvmti/run-tests/test-1943/Android.bp hostsidetests/jvmti/run-tests/test-1943/app/Android.bp hostsidetests/jvmti/run-tests/test-1953/Android.bp hostsidetests/jvmti/run-tests/test-1953/app/Android.bp hostsidetests/jvmti/run-tests/test-1958/Android.bp hostsidetests/jvmti/run-tests/test-1958/app/Android.bp hostsidetests/jvmti/run-tests/test-1962/Android.bp hostsidetests/jvmti/run-tests/test-1962/app/Android.bp hostsidetests/jvmti/run-tests/test-1967/Android.bp hostsidetests/jvmti/run-tests/test-1967/app/Android.bp hostsidetests/jvmti/run-tests/test-1968/Android.bp hostsidetests/jvmti/run-tests/test-1968/app/Android.bp hostsidetests/jvmti/run-tests/test-1969/Android.bp hostsidetests/jvmti/run-tests/test-1969/app/Android.bp hostsidetests/jvmti/run-tests/test-1970/Android.bp hostsidetests/jvmti/run-tests/test-1970/app/Android.bp hostsidetests/jvmti/run-tests/test-1971/Android.bp hostsidetests/jvmti/run-tests/test-1971/app/Android.bp hostsidetests/jvmti/run-tests/test-1974/Android.bp hostsidetests/jvmti/run-tests/test-1974/app/Android.bp hostsidetests/jvmti/run-tests/test-1975/Android.bp hostsidetests/jvmti/run-tests/test-1975/app/Android.bp hostsidetests/jvmti/run-tests/test-1976/Android.bp hostsidetests/jvmti/run-tests/test-1976/app/Android.bp hostsidetests/jvmti/run-tests/test-1977/Android.bp hostsidetests/jvmti/run-tests/test-1977/app/Android.bp hostsidetests/jvmti/run-tests/test-1978/Android.bp hostsidetests/jvmti/run-tests/test-1978/app/Android.bp hostsidetests/jvmti/run-tests/test-1979/Android.bp hostsidetests/jvmti/run-tests/test-1979/app/Android.bp hostsidetests/jvmti/run-tests/test-1981/Android.bp hostsidetests/jvmti/run-tests/test-1981/app/Android.bp hostsidetests/jvmti/run-tests/test-1982/Android.bp hostsidetests/jvmti/run-tests/test-1982/app/Android.bp hostsidetests/jvmti/run-tests/test-1983/Android.bp hostsidetests/jvmti/run-tests/test-1983/app/Android.bp hostsidetests/jvmti/run-tests/test-1984/Android.bp hostsidetests/jvmti/run-tests/test-1984/app/Android.bp hostsidetests/jvmti/run-tests/test-1988/Android.bp hostsidetests/jvmti/run-tests/test-1988/app/Android.bp hostsidetests/jvmti/run-tests/test-1989/Android.bp hostsidetests/jvmti/run-tests/test-1989/app/Android.bp hostsidetests/jvmti/run-tests/test-1990/Android.bp hostsidetests/jvmti/run-tests/test-1990/app/Android.bp hostsidetests/jvmti/run-tests/test-1991/Android.bp hostsidetests/jvmti/run-tests/test-1991/app/Android.bp hostsidetests/jvmti/run-tests/test-1992/Android.bp hostsidetests/jvmti/run-tests/test-1992/app/Android.bp hostsidetests/jvmti/run-tests/test-1994/Android.bp hostsidetests/jvmti/run-tests/test-1994/app/Android.bp hostsidetests/jvmti/run-tests/test-1995/Android.bp hostsidetests/jvmti/run-tests/test-1995/app/Android.bp hostsidetests/jvmti/run-tests/test-1996/Android.bp hostsidetests/jvmti/run-tests/test-1996/app/Android.bp hostsidetests/jvmti/run-tests/test-1997/Android.bp hostsidetests/jvmti/run-tests/test-1997/app/Android.bp hostsidetests/jvmti/run-tests/test-1998/Android.bp hostsidetests/jvmti/run-tests/test-1998/app/Android.bp hostsidetests/jvmti/run-tests/test-1999/Android.bp hostsidetests/jvmti/run-tests/test-1999/app/Android.bp hostsidetests/jvmti/run-tests/test-2001/Android.bp hostsidetests/jvmti/run-tests/test-2001/app/Android.bp hostsidetests/jvmti/run-tests/test-2002/Android.bp hostsidetests/jvmti/run-tests/test-2002/app/Android.bp hostsidetests/jvmti/run-tests/test-2003/Android.bp hostsidetests/jvmti/run-tests/test-2003/app/Android.bp hostsidetests/jvmti/run-tests/test-2004/Android.bp hostsidetests/jvmti/run-tests/test-2004/app/Android.bp hostsidetests/jvmti/run-tests/test-2005/Android.bp hostsidetests/jvmti/run-tests/test-2005/app/Android.bp hostsidetests/jvmti/run-tests/test-2006/Android.bp hostsidetests/jvmti/run-tests/test-2006/app/Android.bp hostsidetests/jvmti/run-tests/test-2007/Android.bp hostsidetests/jvmti/run-tests/test-2007/app/Android.bp hostsidetests/jvmti/run-tests/test-902/Android.bp hostsidetests/jvmti/run-tests/test-902/app/Android.bp hostsidetests/jvmti/run-tests/test-903/Android.bp hostsidetests/jvmti/run-tests/test-903/app/Android.bp hostsidetests/jvmti/run-tests/test-904/Android.bp hostsidetests/jvmti/run-tests/test-904/app/Android.bp hostsidetests/jvmti/run-tests/test-905/Android.bp hostsidetests/jvmti/run-tests/test-905/app/Android.bp hostsidetests/jvmti/run-tests/test-906/Android.bp hostsidetests/jvmti/run-tests/test-906/app/Android.bp hostsidetests/jvmti/run-tests/test-907/Android.bp hostsidetests/jvmti/run-tests/test-907/app/Android.bp hostsidetests/jvmti/run-tests/test-908/Android.bp hostsidetests/jvmti/run-tests/test-908/app/Android.bp hostsidetests/jvmti/run-tests/test-910/Android.bp hostsidetests/jvmti/run-tests/test-910/app/Android.bp hostsidetests/jvmti/run-tests/test-911/Android.bp hostsidetests/jvmti/run-tests/test-911/app/Android.bp hostsidetests/jvmti/run-tests/test-912/Android.bp hostsidetests/jvmti/run-tests/test-912/app/Android.bp hostsidetests/jvmti/run-tests/test-913/Android.bp hostsidetests/jvmti/run-tests/test-913/app/Android.bp hostsidetests/jvmti/run-tests/test-914/Android.bp hostsidetests/jvmti/run-tests/test-914/app/Android.bp hostsidetests/jvmti/run-tests/test-915/Android.bp hostsidetests/jvmti/run-tests/test-915/app/Android.bp hostsidetests/jvmti/run-tests/test-917/Android.bp hostsidetests/jvmti/run-tests/test-917/app/Android.bp hostsidetests/jvmti/run-tests/test-918/Android.bp hostsidetests/jvmti/run-tests/test-918/app/Android.bp hostsidetests/jvmti/run-tests/test-919/Android.bp hostsidetests/jvmti/run-tests/test-919/app/Android.bp hostsidetests/jvmti/run-tests/test-920/Android.bp hostsidetests/jvmti/run-tests/test-920/app/Android.bp hostsidetests/jvmti/run-tests/test-922/Android.bp hostsidetests/jvmti/run-tests/test-922/app/Android.bp hostsidetests/jvmti/run-tests/test-923/Android.bp hostsidetests/jvmti/run-tests/test-923/app/Android.bp hostsidetests/jvmti/run-tests/test-924/Android.bp hostsidetests/jvmti/run-tests/test-924/app/Android.bp hostsidetests/jvmti/run-tests/test-926/Android.bp hostsidetests/jvmti/run-tests/test-926/app/Android.bp hostsidetests/jvmti/run-tests/test-927/Android.bp hostsidetests/jvmti/run-tests/test-927/app/Android.bp hostsidetests/jvmti/run-tests/test-928/Android.bp hostsidetests/jvmti/run-tests/test-928/app/Android.bp hostsidetests/jvmti/run-tests/test-930/Android.bp hostsidetests/jvmti/run-tests/test-930/app/Android.bp hostsidetests/jvmti/run-tests/test-931/Android.bp hostsidetests/jvmti/run-tests/test-931/app/Android.bp hostsidetests/jvmti/run-tests/test-932/Android.bp hostsidetests/jvmti/run-tests/test-932/app/Android.bp hostsidetests/jvmti/run-tests/test-940/Android.bp hostsidetests/jvmti/run-tests/test-940/app/Android.bp hostsidetests/jvmti/run-tests/test-942/Android.bp hostsidetests/jvmti/run-tests/test-942/app/Android.bp hostsidetests/jvmti/run-tests/test-944/Android.bp hostsidetests/jvmti/run-tests/test-944/app/Android.bp hostsidetests/jvmti/run-tests/test-945/Android.bp hostsidetests/jvmti/run-tests/test-945/app/Android.bp hostsidetests/jvmti/run-tests/test-947/Android.bp hostsidetests/jvmti/run-tests/test-947/app/Android.bp hostsidetests/jvmti/run-tests/test-951/Android.bp hostsidetests/jvmti/run-tests/test-951/app/Android.bp hostsidetests/jvmti/run-tests/test-982/Android.bp hostsidetests/jvmti/run-tests/test-982/app/Android.bp hostsidetests/jvmti/run-tests/test-983/Android.bp hostsidetests/jvmti/run-tests/test-983/app/Android.bp hostsidetests/jvmti/run-tests/test-984/Android.bp hostsidetests/jvmti/run-tests/test-984/app/Android.bp hostsidetests/jvmti/run-tests/test-985/Android.bp hostsidetests/jvmti/run-tests/test-985/app/Android.bp hostsidetests/jvmti/run-tests/test-986/Android.bp hostsidetests/jvmti/run-tests/test-986/app/Android.bp hostsidetests/jvmti/run-tests/test-988/Android.bp hostsidetests/jvmti/run-tests/test-988/app/Android.bp hostsidetests/jvmti/run-tests/test-989/Android.bp hostsidetests/jvmti/run-tests/test-989/app/Android.bp hostsidetests/jvmti/run-tests/test-990/Android.bp hostsidetests/jvmti/run-tests/test-990/app/Android.bp hostsidetests/jvmti/run-tests/test-991/Android.bp hostsidetests/jvmti/run-tests/test-991/app/Android.bp hostsidetests/jvmti/run-tests/test-992/Android.bp hostsidetests/jvmti/run-tests/test-992/app/Android.bp hostsidetests/jvmti/run-tests/test-993/Android.bp hostsidetests/jvmti/run-tests/test-993/app/Android.bp hostsidetests/jvmti/run-tests/test-994/Android.bp hostsidetests/jvmti/run-tests/test-994/app/Android.bp hostsidetests/jvmti/run-tests/test-995/Android.bp hostsidetests/jvmti/run-tests/test-995/app/Android.bp hostsidetests/jvmti/run-tests/test-996/Android.bp hostsidetests/jvmti/run-tests/test-996/app/Android.bp hostsidetests/jvmti/run-tests/test-997/Android.bp hostsidetests/jvmti/run-tests/test-997/app/Android.bp hostsidetests/jvmti/tagging/Android.bp hostsidetests/jvmti/tagging/app/Android.bp hostsidetests/library/Android.bp hostsidetests/media/Android.bp hostsidetests/media/app/MediaExtractorTest/Android.bp hostsidetests/media/app/MediaMetricsTest/Android.bp hostsidetests/media/app/MediaSessionTest/Android.bp hostsidetests/media/app/MediaSessionTestHelper/Android.bp hostsidetests/media/bitstreams/Android.bp hostsidetests/media/bitstreams/app/Android.bp hostsidetests/media/bitstreams/common/Android.bp hostsidetests/mediaparser/Android.bp hostsidetests/monkey/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.bp hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.bp hostsidetests/multiuser/Android.bp hostsidetests/numberblocking/Android.bp hostsidetests/numberblocking/app/Android.bp hostsidetests/os/Android.bp hostsidetests/os/app/Android.bp hostsidetests/os/test-apps/EnvironmentTestApp/Android.bp hostsidetests/os/test-apps/HostLinkVerificationApp/Android.bp hostsidetests/os/test-apps/InattentiveSleepTestApp/Android.bp hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp hostsidetests/os/test-apps/ProcfsTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp2/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.bp hostsidetests/os/test-apps/StaticSharedLibProviderAppRecursive/Android.bp hostsidetests/os/test-apps/StaticSharedLibTestApp/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.bp hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.bp hostsidetests/packagemanager/codepath/Android.bp hostsidetests/packagemanager/codepath/app/Android.bp hostsidetests/packagemanager/dynamicmime/Android.bp hostsidetests/packagemanager/dynamicmime/app/Android.bp hostsidetests/packagemanager/dynamicmime/common/Android.bp hostsidetests/packagemanager/dynamicmime/test/Android.bp hostsidetests/packagemanager/extractnativelibs/Android.bp hostsidetests/packagemanager/extractnativelibs/apps/Android.bp hostsidetests/packagemanager/installedloadingprogess/deviceside/Android.bp hostsidetests/packagemanager/installedloadingprogess/hostside/Android.bp hostsidetests/packagemanager/installedloadingprogess/testdata/Android.bp hostsidetests/packagemanager/multiuser/Android.bp hostsidetests/packagemanager/multiuser/app/Android.bp hostsidetests/packagemanager/preferredactivity/Android.bp hostsidetests/packagemanager/preferredactivity/apps/testapp/Android.bp hostsidetests/packagemanager/stats/Android.bp hostsidetests/packagemanager/stats/apps/emptyapp/Android.bp hostsidetests/rollback/Android.bp hostsidetests/sample/Android.bp hostsidetests/sample/app/Android.bp hostsidetests/sample/app2/Android.bp hostsidetests/scopedstorage/Android.bp hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp hostsidetests/seccomp/Android.bp hostsidetests/seccomp/app/Android.bp hostsidetests/seccomp/app/jni/Android.bp hostsidetests/security/Android.mk hostsidetests/securitybulletin/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-137878930/Android.bp hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2182/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-4658/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5131/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0814/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-0840/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13194/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13241/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13253/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9472/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9491/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9584/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2018-9585/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2011/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2013/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2019/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2044/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2099/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2115/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2136/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2207/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9347/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0006/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0069/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0226/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0383/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0313/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0318/Android.bp hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/Android.bp hostsidetests/securitybulletin/securityPatch/includes/Android.bp hostsidetests/securitybulletin/test-apps/CVE-2021-0305/Android.bp hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp hostsidetests/settings/Android.bp hostsidetests/settings/app/DeviceOwnerApp/Android.bp hostsidetests/shortcuts/deviceside/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher1/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher2/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher3/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/launcher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher1/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher2/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher3/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nobackup/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4new_wrongkey/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old/Android.bp hostsidetests/shortcuts/deviceside/backup/publisher4old_nomanifest/Android.bp hostsidetests/shortcuts/deviceside/common/Android.bp hostsidetests/shortcuts/deviceside/multiuser/Android.bp hostsidetests/shortcuts/deviceside/upgrade/Android.bp hostsidetests/shortcuts/hostside/Android.bp hostsidetests/signedconfig/app/Android.bp hostsidetests/signedconfig/hostside/Android.bp hostsidetests/stagedinstall/Android.bp hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/Android.bp hostsidetests/statsdatom/Android.bp hostsidetests/statsdatom/apps/statsdapp/Android.bp hostsidetests/sustainedperf/shadertoy_android/jni/Android.bp hostsidetests/systemui/Android.bp hostsidetests/systemui/app/Android.bp hostsidetests/tagging/Android.bp hostsidetests/tagging/common/Android.bp hostsidetests/tagging/manifest_disabled/Android.bp hostsidetests/tagging/manifest_enabled_sdk_29/Android.bp hostsidetests/tagging/manifest_enabled_sdk_30/Android.bp hostsidetests/tagging/sdk_29/Android.bp hostsidetests/tagging/sdk_30/Android.bp hostsidetests/telephony/Android.bp hostsidetests/telephony/devicetest/Android.bp hostsidetests/telephonyprovider/Android.bp hostsidetests/telephonyprovider/devicetest/Android.bp hostsidetests/testharness/Android.bp hostsidetests/testharness/app/Android.bp hostsidetests/theme/Android.mk hostsidetests/theme/app/Android.bp hostsidetests/time/Android.bp hostsidetests/trustedvoice/Android.bp hostsidetests/trustedvoice/app/Android.bp hostsidetests/tv/Android.bp hostsidetests/tv/app/Android.bp hostsidetests/tv/app2/Android.bp hostsidetests/tzdata/Android.bp hostsidetests/ui/Android.mk hostsidetests/ui/appA/Android.bp hostsidetests/ui/appB/Android.bp hostsidetests/ui/control/Android.bp hostsidetests/usage/Android.bp hostsidetests/usage/app/Android.bp hostsidetests/usb/Android.bp hostsidetests/usb/SerialTestApp/Android.bp hostsidetests/userspacereboot/Android.bp hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp hostsidetests/utils/Android.bp hostsidetests/webkit/Android.bp hostsidetests/webkit/app/Android.bp hostsidetests/wifibroadcasts/Android.bp hostsidetests/wifibroadcasts/app/Android.bp libs/deviceutillegacy/Android.bp libs/helpers/core/Android.bp libs/helpers/core/tests/Android.bp libs/helpers/interfaces/Android.bp libs/input/Android.bp libs/install/Android.bp libs/install/testapp/signing/Android.bp libs/json/Android.bp libs/midi/Android.bp libs/rollback/Android.bp libs/runner/Android.bp libs/shim/Android.bp libs/view/Android.bp libs/vogar-expect/Android.bp suite/audio_quality/executable/Android.bp suite/audio_quality/lib/Android.bp suite/audio_quality/test/Android.bp tests/AlarmManager/Android.bp tests/AlarmManager/app/Android.bp tests/BlobStore/Android.bp tests/BlobStore/certs/Android.bp tests/DropBoxManager/Android.bp tests/JobScheduler/Android.bp tests/JobScheduler/JobTestApp/Android.bp tests/JobSchedulerSharedUid/Android.bp tests/JobSchedulerSharedUid/JobSharedUidTestApp/Android.bp tests/JobSchedulerSharedUid/jobperm/Android.bp tests/JobSchedulerSharedUid/shareduid/Android.bp tests/ProcessTest/Android.bp tests/ProcessTest/NoShareUidApp/Android.bp tests/ProcessTest/ShareUidApp/Android.bp tests/acceleration/Android.bp tests/accessibility/Android.bp tests/accessibilityservice/Android.bp tests/accessibilityservice/test-apps/WidgetProvider/Android.bp tests/accessibilityservice/testsdk29/Android.bp tests/admin/Android.bp tests/admin/app/Android.bp tests/app/ActivityManagerApi29Test/Android.bp tests/app/Android.bp tests/app/BadProviderStubs/Android.bp tests/app/CantSaveState1/Android.bp tests/app/CantSaveState2/Android.bp tests/app/NotificationDelegator/Android.bp tests/app/NotificationListener/Android.bp tests/app/NotificationProvider/Android.bp tests/app/NotificationTrampoline/Android.bp tests/app/NotificationTrampolineApi30/Android.bp tests/app/NotificationTrampolineBase/Android.bp tests/app/StorageDelegator/Android.bp tests/app/app/Android.bp tests/app/shared/Android.bp tests/appintegrity/Android.bp tests/apppredictionservice/Android.bp tests/appsearch/Android.bp tests/appsearch/certs/Android.bp tests/aslr/Android.bp tests/attentionservice/Android.bp tests/autofillservice/Android.bp tests/autofillservice/TestAutofillService/Android.bp tests/backup/Android.bp tests/backup/app/Android.bp tests/bugreport/Android.bp tests/camera/Android.bp tests/camera/libctscamera2jni/Android.mk tests/camera/utils/Android.bp tests/contentcaptureservice/Android.bp tests/contentcaptureservice/OutsideOfPackageActivity/Android.bp tests/contentsuggestions/Android.bp tests/controls/Android.bp tests/core/runner-axt/Android.bp tests/devicepolicy/Android.bp tests/filesystem/Android.bp tests/fragment/Android.bp tests/fragment/sdk26/Android.bp tests/framework/base/biometrics/Android.bp tests/framework/base/biometrics/apps/biometrics/Android.bp tests/framework/base/biometrics/apps/fingerprint/Android.bp tests/framework/base/suggestions/Android.bp tests/framework/base/windowmanager/Android.bp tests/framework/base/windowmanager/alertwindowapp/Android.bp tests/framework/base/windowmanager/alertwindowappsdk25/Android.bp tests/framework/base/windowmanager/alertwindowservice/Android.bp tests/framework/base/windowmanager/app/Android.bp tests/framework/base/windowmanager/app27/Android.bp tests/framework/base/windowmanager/app30/Android.bp tests/framework/base/windowmanager/appAShareUid/Android.bp tests/framework/base/windowmanager/appBShareUid/Android.bp tests/framework/base/windowmanager/appDeprecatedSdk/Android.bp tests/framework/base/windowmanager/appDisplaySize/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/Android.bp tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp tests/framework/base/windowmanager/appProfileable/Android.bp tests/framework/base/windowmanager/appSecondUid/Android.bp tests/framework/base/windowmanager/appThirdUid/Android.bp tests/framework/base/windowmanager/app_base/Android.bp tests/framework/base/windowmanager/backgroundactivity/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppA/Android.bp tests/framework/base/windowmanager/backgroundactivity/AppB/Android.bp tests/framework/base/windowmanager/backgroundactivity/common/Android.bp tests/framework/base/windowmanager/dndsourceapp/Android.bp tests/framework/base/windowmanager/dndtargetapp/Android.bp tests/framework/base/windowmanager/dndtargetappsdk23/Android.bp tests/framework/base/windowmanager/jetpack/Android.bp tests/framework/base/windowmanager/overlayappbase/Android.bp tests/framework/base/windowmanager/shared/Android.bp tests/framework/base/windowmanager/testsdk25/Android.bp tests/framework/base/windowmanager/testsdk28/Android.bp tests/framework/base/windowmanager/testsdk29/Android.bp tests/framework/base/windowmanager/translucentapp/Android.bp tests/framework/base/windowmanager/translucentappsdk26/Android.bp tests/framework/base/windowmanager/util/Android.bp tests/input/Android.bp tests/inputmethod/Android.bp tests/inputmethod/mockime/Android.bp tests/inputmethod/mockspellchecker/Android.bp tests/inputmethod/testapp/Android.bp tests/jdwp/Android.bp tests/jdwp/runner/device-side/Android.bp tests/jdwp/runner/host-side/Android.bp tests/leanbackjank/Android.bp tests/leanbackjank/app/Android.bp tests/libcore/jsr166/Android.bp tests/libcore/luni/Android.bp tests/libcore/ojluni/Android.bp tests/libcore/okhttp/Android.bp tests/libcore/runner/Android.bp tests/libcore/wycheproof-bc/Android.bp tests/libcore/wycheproof/Android.bp tests/location/common/Android.bp tests/location/location_coarse/Android.bp tests/location/location_fine/Android.bp tests/location/location_gnss/Android.bp tests/location/location_none/Android.bp tests/location/location_privileged/Android.bp tests/media/Android.bp tests/media/jni/Android.bp tests/mocking/Android.bp tests/mocking/debuggable/Android.bp tests/mocking/extended/Android.bp tests/mocking/inline/Android.bp tests/musicrecognition/Android.bp tests/musicrecognition/OutsideOfPackageService/Android.bp tests/netlegacy22.permission/Android.bp tests/netsecpolicy/Android.bp tests/openglperf2/jni/Android.bp tests/pdf/Android.bp tests/providerui/Android.bp tests/quickaccesswallet/Android.bp tests/rollback/Android.bp tests/sample/Android.bp tests/searchui/Android.bp tests/security/Android.bp tests/sensor/Android.bp tests/sensor/sensorratepermission/Android.bp tests/sensor/sensorratepermission/DebuggableAPI31/Android.bp tests/sensor/sensorratepermission/DirectReportAPI30/Android.bp tests/sensor/sensorratepermission/DirectReportAPI31/Android.bp tests/sensor/sensorratepermission/EventConnectionAPI30/Android.bp tests/sensor/sensorratepermission/EventConnectionAPI31/Android.bp tests/sensor/sensorratepermission/EventConnectionResampling/Android.bp tests/sensor/sensorratepermission/EventConnectionResampling/app/Android.bp tests/sensor/sensorratepermission/ReturnedRateInfo/Android.bp tests/signature/Android.bp tests/signature/api-check/Android.bp tests/signature/api-check/android-test-base-28-api/Android.bp tests/signature/api-check/android-test-base-current-api/Android.bp tests/signature/api-check/android-test-mock-current-api/Android.bp tests/signature/api-check/android-test-runner-current-api/Android.bp tests/signature/api-check/apache-http-legacy-27-api/Android.bp tests/signature/api-check/apache-http-legacy-current-api/Android.bp tests/signature/api-check/apache-http-legacy-uses-library-api/Android.bp tests/signature/api-check/current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-27-api/Android.bp tests/signature/api-check/hidden-api-blocklist-28-api/Android.bp tests/signature/api-check/hidden-api-blocklist-current-api/Android.bp tests/signature/api-check/hidden-api-blocklist-debug-class/Android.bp tests/signature/api-check/hidden-api-blocklist-test-api/Android.bp tests/signature/api-check/hidden-api-killswitch-debug-class/Android.bp tests/signature/api-check/hidden-api-killswitch-sdklist/Android.bp tests/signature/api-check/hidden-api-killswitch-wildcard/Android.bp tests/signature/api-check/shared-libs-api/Android.mk tests/signature/api-check/system-annotation/Android.bp tests/signature/api-check/system-api/Android.mk tests/signature/api/Android.bp tests/signature/api/Android.mk tests/signature/dex-checker/Android.bp tests/signature/intent-check/Android.bp tests/signature/lib/android/Android.bp tests/signature/lib/common/Android.bp tests/signature/tests/Android.bp tests/simplecpu/jni/Android.bp tests/suspendapps/Android.bp tests/suspendapps/permission/Android.bp tests/suspendapps/test-apps/SuspendTestApp/Android.bp tests/suspendapps/test-apps/TestDeviceAdmin/Android.bp tests/suspendapps/tests/Android.bp tests/tests/accounts/Android.bp tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.bp tests/tests/accounts/common/Android.bp tests/tests/animation/Android.bp tests/tests/apache-http/Android.bp tests/tests/app.usage/Android.bp tests/tests/app.usage/TestApp1/Android.bp tests/tests/app.usage/TestApp2/Android.bp tests/tests/app/Android.bp tests/tests/appcomponentfactory/Android.bp tests/tests/appenumeration/Android.bp tests/tests/appenumeration/app/source/Android.bp tests/tests/appenumeration/app/target/Android.bp tests/tests/appenumeration/lib/Android.bp tests/tests/appop/Android.bp tests/tests/appop/AppInBackground/Android.bp tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp tests/tests/appop/AppThatUsesAppOps/Android.bp tests/tests/appop/AppToBlame1/Android.bp tests/tests/appop/AppToBlame2/Android.bp tests/tests/appop/AppToCollect/Android.bp tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp tests/tests/appop/AppWithDuplicateAttribution/Android.bp tests/tests/appop/AppWithLongAttributionTag/Android.bp tests/tests/appop/AppWithTooManyAttributions/Android.bp tests/tests/appop/aidl/AppOpsForegroundControlService/Android.bp tests/tests/appop/aidl/AppOpsUserService/Android.bp tests/tests/appop/appopsTestUtilLib/Android.bp tests/tests/appop2/Android.bp tests/tests/appwidget/Android.bp tests/tests/appwidget/packages/launchermanifest/Android.bp tests/tests/appwidget/packages/widgetprovider/Android.bp tests/tests/assist/Android.bp tests/tests/assist/common/Android.bp tests/tests/assist/service/Android.bp tests/tests/assist/testapp/Android.bp tests/tests/background/Android.bp tests/tests/batterysaving/Android.bp tests/tests/batterysaving/apps/app_target_api_25/Android.bp tests/tests/batterysaving/apps/app_target_api_current/Android.bp tests/tests/batterysaving/common/Android.bp tests/tests/binder_ndk/Android.bp tests/tests/binder_ndk/libbinder_ndk_test/Android.bp tests/tests/bionic/Android.mk tests/tests/bionic_app/Android.bp tests/tests/bluetooth/Android.bp tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp tests/tests/calendarcommon/Android.bp tests/tests/calendarprovider/Android.bp tests/tests/car/Android.bp tests/tests/carrierapi/Android.bp tests/tests/classloaderfactory/Android.bp tests/tests/classloaderfactory/test-memcl/Android.bp tests/tests/classloaderfactory/test-pathcl/Android.bp tests/tests/colormode/Android.bp tests/tests/contactsprovider/Android.bp tests/tests/contactsprovider/gal/Android.bp tests/tests/contactsproviderwipe/Android.bp tests/tests/content/Android.bp tests/tests/content/BinderPermissionTestService/Android.bp tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.bp tests/tests/content/DirectBootUnawareTestApp/Android.bp tests/tests/content/HelloWorldApp/Android.bp tests/tests/content/PackagePropertyTestApp/Android.bp tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp tests/tests/content/SyncAccountAccessStubs/Android.bp tests/tests/content/app/Android.bp tests/tests/content/emptytestapp/Android.bp tests/tests/content/jni/Android.bp tests/tests/content/lib/accountaccess/Android.bp tests/tests/content/pm/SecureFrp/Android.bp tests/tests/cronet/Android.bp tests/tests/database/Android.bp tests/tests/database/apps/Android.bp tests/tests/deviceconfig/Android.bp tests/tests/display/Android.bp tests/tests/dpi/Android.bp tests/tests/dpi2/Android.bp tests/tests/dreams/Android.bp tests/tests/drm/Android.bp tests/tests/drm/jni/Android.bp tests/tests/drm/lib/Android.bp tests/tests/dynamic_linker/Android.bp tests/tests/effect/Android.bp tests/tests/externalservice/Android.bp tests/tests/externalservice/common/Android.bp tests/tests/externalservice/service/Android.bp tests/tests/gesture/Android.bp tests/tests/graphics/Android.bp tests/tests/graphics/jni/Android.bp tests/tests/gwp-asan/enabled/Android.bp tests/tests/hardware/Android.bp tests/tests/hardware/jni/Android.bp tests/tests/icu/Android.bp tests/tests/icu/icu4c_testapp/Android.bp tests/tests/identity/Android.bp tests/tests/instantapp/Android.bp tests/tests/jni/Android.bp tests/tests/jni/libjnicommon/Android.bp tests/tests/jni/libjnitest/Android.bp tests/tests/jvmti/attaching/Android.bp tests/tests/jvmti/attaching/jni/Android.bp tests/tests/keystore/Android.bp tests/tests/libcoreapievolution/Android.bp tests/tests/libcorefileio/Android.bp tests/tests/libcorelegacy22/Android.bp tests/tests/libnativehelper/Android.bp tests/tests/libnativehelper/jni/Android.bp tests/tests/libthermalndk/Android.bp tests/tests/libthermalndk/jni/Android.bp tests/tests/match_flags/Android.bp tests/tests/match_flags/app/a/Android.bp tests/tests/match_flags/app/b/Android.bp tests/tests/media/libaudiojni/Android.bp tests/tests/media/libimagereaderjni/Android.bp tests/tests/media/libndkaudio/Android.bp tests/tests/mediaparser/Android.bp tests/tests/mediastress/Android.bp tests/tests/mediastress/jni/Android.bp tests/tests/mediatranscoding/Android.bp tests/tests/midi/Android.bp tests/tests/mimemap/Android.bp tests/tests/multiuser/Android.bp tests/tests/nativehardware/Android.bp tests/tests/nativehardware/jni/Android.bp tests/tests/nativemedia/aaudio/jni/Android.mk tests/tests/nativemedia/mediametrics/Android.bp tests/tests/nativemedia/sl/Android.mk tests/tests/nativemedia/xa/Android.mk tests/tests/nativemidi/jni/Android.mk tests/tests/ndef/Android.bp tests/tests/netpermission/internetpermission/Android.bp tests/tests/netpermission/updatestatspermission/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-false/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-true/Android.bp tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.bp tests/tests/networksecurityconfig/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.bp tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.bp tests/tests/neuralnetworks/Android.mk tests/tests/neuralnetworks/tflite_delegate/Android.mk tests/tests/nfc/Android.bp tests/tests/notificationlegacy/notificationlegacy20/Android.bp tests/tests/notificationlegacy/notificationlegacy27/Android.bp tests/tests/notificationlegacy/notificationlegacy28/Android.bp tests/tests/notificationlegacy/notificationlegacy29/Android.bp tests/tests/notificationlegacy/notificationlegacy30/Android.bp tests/tests/opengl/Android.bp tests/tests/opengl/libopengltest/Android.bp tests/tests/openglperf/Android.bp tests/tests/openglperf/jni/Android.bp tests/tests/os/Android.bp tests/tests/os/Android.mk tests/tests/os/AutoRevokeQApp/Android.bp tests/tests/os/AutoRevokeRApp/Android.bp tests/tests/os/AutoRevokeSApp/Android.bp tests/tests/os/CompanionTestApp/Android.bp tests/tests/os/jni/Android.bp tests/tests/packageinstaller/adminpackageinstaller/Android.bp tests/tests/packageinstaller/atomicinstall/Android.bp tests/tests/packageinstaller/install/Android.bp tests/tests/packageinstaller/install_appop_default/Android.bp tests/tests/packageinstaller/install_appop_denied/Android.bp tests/tests/packageinstaller/nopermission/Android.bp tests/tests/packageinstaller/nopermission25/Android.bp tests/tests/packageinstaller/tapjacking/Android.bp tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp tests/tests/packageinstaller/test-apps/emptytestapp/Android.bp tests/tests/packageinstaller/uninstall/Android.bp tests/tests/packagewatchdog/Android.bp tests/tests/permission/Android.bp tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionA/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp tests/tests/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp tests/tests/permission/AppThatDefinesPermissionA/Android.bp tests/tests/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp tests/tests/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp tests/tests/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp tests/tests/permission/AppThatRequestContactsPermission15/Android.bp tests/tests/permission/AppThatRequestContactsPermission16/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission22/Android.bp tests/tests/permission/AppThatRequestLocationPermission28/Android.bp tests/tests/permission/AppThatRequestLocationPermission29/Android.bp tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp tests/tests/permission/AppThatRequestOneTimePermission/Android.bp tests/tests/permission/AppThatRequestPermissionAandB/Android.bp tests/tests/permission/AppThatRequestPermissionAandC/Android.bp tests/tests/permission/AppThatRequestStoragePermission28/Android.bp tests/tests/permission/AppThatRequestStoragePermission29/Android.bp tests/tests/permission/AppThatRunsRationaleTests/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp tests/tests/permission/StorageEscalationApp28/Android.bp tests/tests/permission/StorageEscalationApp29Full/Android.bp tests/tests/permission/StorageEscalationApp29Scoped/Android.bp tests/tests/permission/jni/Android.bp tests/tests/permission/nativeTests/Android.bp tests/tests/permission/permissionTestUtilLib/Android.bp tests/tests/permission/sdk28/Android.bp tests/tests/permission/telephony/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp tests/tests/permission2/Android.bp tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk30/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp tests/tests/permission3/Android.bp tests/tests/permission3/PermissionPolicyApp25/Android.bp tests/tests/permission3/UsePermissionApp22/Android.bp tests/tests/permission3/UsePermissionApp22CalendarOnly/Android.bp tests/tests/permission3/UsePermissionApp22None/Android.bp tests/tests/permission3/UsePermissionApp23/Android.bp tests/tests/permission3/UsePermissionApp25/Android.bp tests/tests/permission3/UsePermissionApp26/Android.bp tests/tests/permission3/UsePermissionApp28/Android.bp tests/tests/permission3/UsePermissionApp29/Android.bp tests/tests/permission3/UsePermissionApp30/Android.bp tests/tests/permission3/UsePermissionApp30WithBackground/Android.bp tests/tests/permission3/UsePermissionAppLatest/Android.bp tests/tests/permission3/UsePermissionAppLatestNone/Android.bp tests/tests/permission3/UsePermissionAppWithOverlay/Android.bp tests/tests/permission4/Android.bp tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp tests/tests/preference/Android.bp tests/tests/print/Android.bp tests/tests/print/ExternalPrintService/Android.bp tests/tests/print/printTestUtilLib/Android.bp tests/tests/proto/Android.bp tests/tests/provider/Android.bp tests/tests/provider/app/GalleryTestApp/Android.bp tests/tests/provider/preconditions/Android.bp tests/tests/renderscript/libcoremathtestcpp/Android.bp tests/tests/resolverservice/Android.bp tests/tests/resourcesloader/Android.bp tests/tests/resourcesloader/resources/Android.bp tests/tests/role/Android.bp tests/tests/role/CtsRoleTestApp/Android.bp tests/tests/role/CtsRoleTestApp28/Android.bp tests/tests/rsblas/libbnnmdata/Android.bp tests/tests/rscpp/librscpptest/Android.mk tests/tests/sax/Android.bp tests/tests/secure_element/access_control/AccessControlApp1/Android.bp tests/tests/secure_element/access_control/AccessControlApp2/Android.bp tests/tests/secure_element/access_control/AccessControlApp3/Android.bp tests/tests/secure_element/omapi/Android.bp tests/tests/security/Android.bp tests/tests/security/jni/Android.bp tests/tests/security/native/encryption/Android.bp tests/tests/security/native/verified_boot/Android.bp tests/tests/security/testeffect/Android.bp tests/tests/selinux/common/jni/Android.bp tests/tests/selinux/selinuxEphemeral/Android.bp tests/tests/selinux/selinuxTargetSdk25/Android.bp tests/tests/selinux/selinuxTargetSdk27/Android.bp tests/tests/selinux/selinuxTargetSdk28/Android.bp tests/tests/selinux/selinuxTargetSdk29/Android.bp tests/tests/selinux/selinuxTargetSdkCurrent/Android.bp tests/tests/settings/Android.bp tests/tests/sharesheet/Android.bp tests/tests/sharesheet/packages/Android.bp tests/tests/shortcutmanager/Android.bp tests/tests/simphonebookprovider/Android.bp tests/tests/simphonebookprovider/nosim/Android.bp tests/tests/simpleperf/Android.mk tests/tests/simpleperf/CtsSimpleperfDebuggableApp/Android.bp tests/tests/simpleperf/CtsSimpleperfProfileableApp/Android.bp tests/tests/slice/Android.bp tests/tests/soundtrigger/Android.bp tests/tests/speech/Android.bp tests/tests/syncmanager/Android.bp tests/tests/syncmanager/apps/Android.bp tests/tests/syncmanager/common/Android.bp tests/tests/systemintents/Android.bp tests/tests/systemui/Android.bp tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp tests/tests/systemui/AudioRecorderTestApp_Base/Android.bp tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp tests/tests/systemui/PipTestApp/Android.bp tests/tests/systemui/common/Android.bp tests/tests/telecom/Android.bp tests/tests/telecom/Api29InCallServiceTestApp/Android.bp tests/tests/telecom/CallRedirectionServiceTestApp/Android.bp tests/tests/telecom/CallScreeningServiceTestApp/Android.bp tests/tests/telecom/CarModeTestApp/Android.bp tests/tests/telecom/CarModeTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyDialerTestApp/Android.bp tests/tests/telecom/ThirdPtyDialerTestAppTwo/Android.bp tests/tests/telecom/ThirdPtyInCallServiceTestApp/Android.bp tests/tests/telecom2/Android.bp tests/tests/telecom3/Android.bp tests/tests/telephony/TestFinancialSmsApp/Android.bp tests/tests/telephony/TestSmsApp/Android.bp tests/tests/telephony/TestSmsApp22/Android.bp tests/tests/telephony/TestSmsRetrieverApp/Android.bp tests/tests/telephony/current/Android.bp tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/Android.bp tests/tests/telephony/current/LocationAccessingApp/sdk28/Android.bp tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp tests/tests/telephony/current/permissions/Android.bp tests/tests/telephony/current/preconditions/Android.bp tests/tests/telephony/current/preconditions/app/Android.bp tests/tests/telephony/current/src/android/telephony/cts/util/Android.bp tests/tests/telephony/sdk28/Android.bp tests/tests/telephony2/Android.bp tests/tests/telephony3/Android.bp tests/tests/telephony4/Android.bp tests/tests/telephony4/certs/Android.bp tests/tests/telephonyprovider/Android.bp tests/tests/text/Android.bp tests/tests/text/jni/Android.bp tests/tests/textclassifier/Android.bp tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp tests/tests/theme/Android.bp tests/tests/time/Android.bp tests/tests/toast/Android.bp tests/tests/toastlegacy/Android.bp tests/tests/tools/processors/view_inspector/Android.bp tests/tests/transition/Android.bp tests/tests/tv/Android.bp tests/tests/uiautomation/Android.bp tests/tests/uidisolation/Android.bp tests/tests/uirendering/Android.bp tests/tests/uirendering/jni/Android.bp tests/tests/uirendering27/Android.bp tests/tests/usb/Android.bp tests/tests/util/Android.bp tests/tests/vcn/Android.bp tests/tests/view/jni/Android.bp tests/tests/view/sdk28/Android.bp tests/tests/view/surfacevalidator/Android.bp tests/tests/voiceRecognition/Android.bp tests/tests/voiceRecognition/RecognitionService/Android.bp tests/tests/voiceinteraction/Android.bp tests/tests/voiceinteraction/common/Android.bp tests/tests/voiceinteraction/service/Android.bp tests/tests/voiceinteraction/testapp/Android.bp tests/tests/voicesettings/Android.bp tests/tests/voicesettings/service/Android.bp tests/tests/webkit/Android.bp tests/tests/widget/Android.bp tests/tests/widget/app/Android.bp tests/tests/widget29/Android.bp tests/tests/wifi/Android.bp tests/tests/wifi/CtsWifiLocationTestApp/Android.bp tests/tvprovider/Android.bp tests/uwb/Android.bp tests/video/Android.bp tests/vr/Android.bp tests/vr/jni/Android.bp tools/cfassembler/Android.bp tools/cts-api-coverage/Android.bp tools/cts-device-info/jni/Android.bp tools/cts-dynamic-config/Android.mk tools/cts-holo-generation/Android.bp tools/cts-media-preparer-app/Android.bp tools/cts-preconditions/Android.bp tools/cts-tradefed/Android.bp tools/cts-tradefed/tests/Android.bp tools/device-setup/TestDeviceSetup/Android.bp tools/manifest-generator/Android.bp tools/manifest-generator/tests/Android.bp tools/release-parser/Android.bp tools/release-parser/tests/Android.bp tools/vm-tests-tf/Android.bp tools/vm-tests-tf/Android.mk tools/vm-tests-tf/targetprep/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD to: libs/testserver/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY to: apps/CtsVerifier/Android.bp apps/CtsVerifier/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-CC-BY SPDX-license-identifier-MIT SPDX-license-identifier-NCSA legacy_unencumbered to: Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/Android.mk Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-CC-BY legacy_unencumbered to: tests/tests/media/Android.bp Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT to: hostsidetests/gputools/Android.bp hostsidetests/gputools/layers/Android.bp Added SPDX-license-identifier-Apache-2.0 legacy_unencumbered to: tests/tests/media/libmediandkjni/Android.bp Added SPDX-license-identifier-BSD SPDX-license-identifier-MIT SPDX-license-identifier-NCSA to: hostsidetests/sustainedperf/dhrystone/Android.mk Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I1e2c8b51fbdcf8bd51dd1791fdca5d6e549ce172 Merged-in: Iceb1641ab8d94a4387136e3e7b6cda3d5cde857f --- Vcn/tests/cts/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 5666ee78a5..ecb1236b9b 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test { name: "CtsVcnTestCases", defaults: ["cts_defaults"], From 26258d185caf25afa934fc37fe514aaf7f4b690b Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 17:17:27 -0800 Subject: [PATCH 0091/1057] CTS test VcnNetworkPolicyListener APIs. This CL creates CTS testing for VcnNetworkPolicyListener APIs. Specifically, a test-version of VcnNetworkPolicyListener is defined and used to add/remove from VcnManager. Also, verify that VcnManager#applyVcnNetworkPolicy throws when the caller does not have permission NETWORK_FACTORY. Bug: 180549391 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I69ce34f04f6d2fe8d78f29b3cf1ee10d4ee0531a --- .../android/net/vcn/cts/VcnManagerTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index b92f079120..4e5e82119a 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -28,6 +28,8 @@ import static org.junit.Assume.assumeTrue; import android.content.Context; import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; @@ -52,12 +54,18 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnManagerTest { private static final String TAG = VcnManagerTest.class.getSimpleName(); + private static final int TIMEOUT_MS = 500; + + private static final Executor INLINE_EXECUTOR = Runnable::run; + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; @@ -174,4 +182,45 @@ public class VcnManagerTest { }); }); } + + /** Test implementation of VcnNetworkPolicyListener for verification purposes. */ + private static class TestVcnNetworkPolicyListener + implements VcnManager.VcnNetworkPolicyListener { + private final CompletableFuture mFutureOnPolicyChanged = new CompletableFuture<>(); + + @Override + public void onPolicyChanged() { + mFutureOnPolicyChanged.complete(null /* unused */); + } + + public void awaitOnPolicyChanged() throws Exception { + mFutureOnPolicyChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + @Test(expected = SecurityException.class) + public void testAddVcnNetworkPolicyListener_noNetworkFactoryPermission() throws Exception { + final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + + try { + mVcnManager.addVcnNetworkPolicyListener(INLINE_EXECUTOR, listener); + } finally { + mVcnManager.removeVcnNetworkPolicyListener(listener); + } + } + + @Test + public void testRemoveVcnNetworkPolicyListener() { + final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + + mVcnManager.removeVcnNetworkPolicyListener(listener); + } + + @Test(expected = SecurityException.class) + public void testApplyVcnNetworkPolicy_noNetworkFactoryPermission() throws Exception { + final NetworkCapabilities nc = new NetworkCapabilities.Builder().build(); + final LinkProperties lp = new LinkProperties(); + + mVcnManager.applyVcnNetworkPolicy(nc, lp); + } } From 6ea304125e7a08cfed94221b0e1cb7420696aab7 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 17:35:10 -0800 Subject: [PATCH 0092/1057] CTS test VcnStatusCallback. This CL adds CTS test coverage for VcnStatusCallback related APIs. Specifically, VcnStatusCallbacks are registered and unregistered. Additionally, #onVcnStatusChanged is verified. Bug: 180550123 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I289b0a742864a66c1c4668c712e3914f93fabb2b --- .../android/net/vcn/cts/VcnManagerTest.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 4e5e82119a..a5646fa1f6 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -22,10 +22,13 @@ import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkProperties; @@ -223,4 +226,104 @@ public class VcnManagerTest { mVcnManager.applyVcnNetworkPolicy(nc, lp); } + + /** Test implementation of VcnStatusCallback for verification purposes. */ + private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { + private final CompletableFuture mFutureOnVcnStatusChanged = + new CompletableFuture<>(); + private final CompletableFuture mFutureOnGatewayConnectionError = + new CompletableFuture<>(); + + @Override + public void onVcnStatusChanged(int statusCode) { + mFutureOnVcnStatusChanged.complete(statusCode); + } + + @Override + public void onGatewayConnectionError( + @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) { + mFutureOnGatewayConnectionError.complete( + new GatewayConnectionError(networkCapabilities, errorCode, detail)); + } + + public int awaitOnVcnStatusChanged() throws Exception { + return mFutureOnVcnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception { + return mFutureOnGatewayConnectionError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + /** Info class for organizing VcnStatusCallback#onGatewayConnectionError response data. */ + private static class GatewayConnectionError { + @NonNull public final int[] networkCapabilities; + public final int errorCode; + @Nullable public final Throwable detail; + + public GatewayConnectionError( + @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) { + this.networkCapabilities = networkCapabilities.clone(); + this.errorCode = errorCode; + this.detail = detail; + } + } + + private void registerVcnStatusCallbackForSubId( + @NonNull TestVcnStatusCallback callback, int subId) throws Exception { + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback); + }); + }); + } + + @Test + public void testRegisterVcnStatusCallback() throws Exception { + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + + try { + registerVcnStatusCallbackForSubId(callback, subId); + + final int statusCode = callback.awaitOnVcnStatusChanged(); + assertEquals(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED, statusCode); + } finally { + mVcnManager.unregisterVcnStatusCallback(callback); + } + } + + @Test + public void testRegisterVcnStatusCallback_reuseUnregisteredCallback() throws Exception { + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + + try { + registerVcnStatusCallbackForSubId(callback, subId); + mVcnManager.unregisterVcnStatusCallback(callback); + registerVcnStatusCallbackForSubId(callback, subId); + } finally { + mVcnManager.unregisterVcnStatusCallback(callback); + } + } + + @Test(expected = IllegalStateException.class) + public void testRegisterVcnStatusCallback_duplicateRegister() throws Exception { + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + + try { + registerVcnStatusCallbackForSubId(callback, subId); + registerVcnStatusCallbackForSubId(callback, subId); + } finally { + mVcnManager.unregisterVcnStatusCallback(callback); + } + } + + @Test + public void testUnregisterVcnStatusCallback() throws Exception { + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + + mVcnManager.unregisterVcnStatusCallback(callback); + } } From 34f1561074a28b4e59665496cee5d9136078ac21 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Feb 2021 15:37:01 -0800 Subject: [PATCH 0093/1057] Support converting IkeSaProposal to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(new tests added) Change-Id: I108e5a946296f65bbe92549464aa68a2ec453659 --- .../IkeSaProposalUtils.java | 87 +++++++++++++++++ .../SaProposalUtilsBase.java | 96 +++++++++++++++++++ .../SaProposalUtilsTest.java | 55 +++++++++++ 3 files changed, 238 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java new file mode 100644 index 0000000000..1459671f41 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java @@ -0,0 +1,87 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.IkeSaProposal; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert IkeSaProposal to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeSaProposalUtils extends SaProposalUtilsBase { + private static final String PRF_KEY = "PRF_KEY"; + + /** Serializes an IkeSaProposal to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(IkeSaProposal proposal) { + final PersistableBundle result = SaProposalUtilsBase.toPersistableBundle(proposal); + + final int[] prfArray = + proposal.getPseudorandomFunctions().stream().mapToInt(i -> i).toArray(); + result.putIntArray(PRF_KEY, prfArray); + + return result; + } + + /** Constructs an IkeSaProposal by deserializing a PersistableBundle. */ + @NonNull + public static IkeSaProposal fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); + + final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY); + Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null"); + final List encryptList = + PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new); + for (EncryptionAlgoKeyLenPair t : encryptList) { + builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen); + } + + final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY); + Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null"); + for (int algo : integrityAlgoIdArray) { + builder.addIntegrityAlgorithm(algo); + } + + final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY); + Objects.requireNonNull(dhGroupArray, "DH Group array was null"); + for (int dh : dhGroupArray) { + builder.addDhGroup(dh); + } + + final int[] prfArray = in.getIntArray(PRF_KEY); + Objects.requireNonNull(prfArray, "PRF array was null"); + for (int prf : prfArray) { + builder.addPseudorandomFunction(prf); + } + + return builder.build(); + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java new file mode 100644 index 0000000000..0c9ee84327 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java @@ -0,0 +1,96 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import android.annotation.NonNull; +import android.net.ipsec.ike.SaProposal; +import android.os.PersistableBundle; +import android.util.Pair; + +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Abstract utility class to convert SaProposal to/from PersistableBundle. + * + * @hide + */ +abstract class SaProposalUtilsBase { + static final String ENCRYPT_ALGO_KEY = "ENCRYPT_ALGO_KEY"; + static final String INTEGRITY_ALGO_KEY = "INTEGRITY_ALGO_KEY"; + static final String DH_GROUP_KEY = "DH_GROUP_KEY"; + + static class EncryptionAlgoKeyLenPair { + private static final String ALGO_KEY = "ALGO_KEY"; + private static final String KEY_LEN_KEY = "KEY_LEN_KEY"; + + public final int encryptionAlgo; + public final int keyLen; + + EncryptionAlgoKeyLenPair(int encryptionAlgo, int keyLen) { + this.encryptionAlgo = encryptionAlgo; + this.keyLen = keyLen; + } + + EncryptionAlgoKeyLenPair(PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + this.encryptionAlgo = in.getInt(ALGO_KEY); + this.keyLen = in.getInt(KEY_LEN_KEY); + } + + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(ALGO_KEY, encryptionAlgo); + result.putInt(KEY_LEN_KEY, keyLen); + + return result; + } + } + + /** + * Serializes common info of a SaProposal to a PersistableBundle. + * + * @hide + */ + @NonNull + static PersistableBundle toPersistableBundle(SaProposal proposal) { + final PersistableBundle result = new PersistableBundle(); + + final List encryptAlgoKeyLenPairs = new ArrayList<>(); + for (Pair pair : proposal.getEncryptionAlgorithms()) { + encryptAlgoKeyLenPairs.add(new EncryptionAlgoKeyLenPair(pair.first, pair.second)); + } + final PersistableBundle encryptionBundle = + PersistableBundleUtils.fromList( + encryptAlgoKeyLenPairs, EncryptionAlgoKeyLenPair::toPersistableBundle); + result.putPersistableBundle(ENCRYPT_ALGO_KEY, encryptionBundle); + + final int[] integrityAlgoIdArray = + proposal.getIntegrityAlgorithms().stream().mapToInt(i -> i).toArray(); + result.putIntArray(INTEGRITY_ALGO_KEY, integrityAlgoIdArray); + + final int[] dhGroupArray = proposal.getDhGroups().stream().mapToInt(i -> i).toArray(); + result.putIntArray(DH_GROUP_KEY, dhGroupArray); + + return result; + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java new file mode 100644 index 0000000000..d3d3a2c5c8 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -0,0 +1,55 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.SaProposal; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SaProposalUtilsTest { + @Test + public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { + final IkeSaProposal proposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) + .build(); + + final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal); + final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle); + + assertEquals(proposal, resultProposal); + } +} From 768fd7942a24da8d01e9bab7ebcbf515a257cbc7 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Feb 2021 17:03:51 -0800 Subject: [PATCH 0094/1057] Support converting ChildSaProposal to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(new tests added) Change-Id: I726a29a65b10b23718fe3b1658d70a8b84cfd2de --- .../ChildSaProposalUtils.java | 73 +++++++++++++++++++ .../SaProposalUtilsTest.java | 21 ++++++ 2 files changed, 94 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java new file mode 100644 index 0000000000..ce5ec75f01 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java @@ -0,0 +1,73 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.ChildSaProposal; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert ChildSaProposal to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class ChildSaProposalUtils extends SaProposalUtilsBase { + /** Serializes a ChildSaProposal to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(ChildSaProposal proposal) { + return SaProposalUtilsBase.toPersistableBundle(proposal); + } + + /** Constructs a ChildSaProposal by deserializing a PersistableBundle. */ + @NonNull + public static ChildSaProposal fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); + + final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY); + Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null"); + final List encryptList = + PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new); + for (EncryptionAlgoKeyLenPair t : encryptList) { + builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen); + } + + final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY); + Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null"); + for (int algo : integrityAlgoIdArray) { + builder.addIntegrityAlgorithm(algo); + } + + final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY); + Objects.requireNonNull(dhGroupArray, "DH Group array was null"); + for (int dh : dhGroupArray) { + builder.addDhGroup(dh); + } + + return builder.build(); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java index d3d3a2c5c8..e9e8e2444d 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -18,6 +18,7 @@ package android.net.vcn.persistablebundleutils; import static org.junit.Assert.assertEquals; +import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.SaProposal; import android.os.PersistableBundle; @@ -52,4 +53,24 @@ public class SaProposalUtilsTest { assertEquals(proposal, resultProposal); } + + @Test + public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception { + final ChildSaProposal proposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.KEY_LEN_AES_192) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP) + .build(); + + final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal); + final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle); + + assertEquals(proposal, resultProposal); + } } From c53e17e38ca2ff5653375e68f7035e98aa2172c2 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Feb 2021 18:46:12 -0800 Subject: [PATCH 0095/1057] Support converting TunnelModeChildSessionParams to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I4d27ac37ce750930cefa73de25e5deea74591d0e --- .../TunnelModeChildSessionParamsUtils.java | 117 ++++++++++++++++++ .../SaProposalUtilsTest.java | 24 ++-- ...TunnelModeChildSessionParamsUtilsTest.java | 91 ++++++++++++++ 3 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java new file mode 100644 index 0000000000..66a4330924 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java @@ -0,0 +1,117 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert TunnelModeChildSessionParams to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class TunnelModeChildSessionParamsUtils { + private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY"; + private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY"; + private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; + private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; + private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; + + /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(TunnelModeChildSessionParams params) { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle saProposalBundle = + PersistableBundleUtils.fromList( + params.getSaProposals(), ChildSaProposalUtils::toPersistableBundle); + result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle); + + final PersistableBundle inTsBundle = + PersistableBundleUtils.fromList( + params.getInboundTrafficSelectors(), + IkeTrafficSelectorUtils::toPersistableBundle); + result.putPersistableBundle(INBOUND_TS_KEY, inTsBundle); + + final PersistableBundle outTsBundle = + PersistableBundleUtils.fromList( + params.getOutboundTrafficSelectors(), + IkeTrafficSelectorUtils::toPersistableBundle); + result.putPersistableBundle(OUTBOUND_TS_KEY, outTsBundle); + + result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); + result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); + + // TODO: b/163604823 Support serializing configuration requests. + + return result; + } + + private static List getTsFromPersistableBundle( + PersistableBundle in, String key) { + PersistableBundle tsBundle = in.getPersistableBundle(key); + Objects.requireNonNull(tsBundle, "Value for key " + key + " was null"); + return PersistableBundleUtils.toList( + tsBundle, IkeTrafficSelectorUtils::fromPersistableBundle); + } + + /** Constructs a TunnelModeChildSessionParams by deserializing a PersistableBundle. */ + @NonNull + public static TunnelModeChildSessionParams fromPersistableBundle( + @NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final TunnelModeChildSessionParams.Builder builder = + new TunnelModeChildSessionParams.Builder(); + + final PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY); + Objects.requireNonNull(proposalBundle, "SA proposal was null"); + final List proposals = + PersistableBundleUtils.toList( + proposalBundle, ChildSaProposalUtils::fromPersistableBundle); + for (ChildSaProposal p : proposals) { + builder.addSaProposal(p); + } + + for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) { + builder.addInboundTrafficSelectors(ts); + } + + for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) { + builder.addOutboundTrafficSelectors(ts); + } + + builder.setLifetimeSeconds( + in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); + + // TODO: b/163604823 Support deserializing configuration requests. + + return builder.build(); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java index e9e8e2444d..8ae8692b4f 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -54,19 +54,21 @@ public class SaProposalUtilsTest { assertEquals(proposal, resultProposal); } + /** Package private so that TunnelModeChildSessionParamsUtilsTest can use it */ + static ChildSaProposal buildTestChildSaProposal() { + return new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_192) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP) + .build(); + } + @Test public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception { - final ChildSaProposal proposal = - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, - SaProposal.KEY_LEN_AES_128) - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, - SaProposal.KEY_LEN_AES_192) - .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) - .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP) - .build(); + final ChildSaProposal proposal = buildTestChildSaProposal(); final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal); final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle); diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java new file mode 100644 index 0000000000..b757aa2b4e --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java @@ -0,0 +1,91 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TunnelModeChildSessionParamsUtilsTest { + private TunnelModeChildSessionParams.Builder createBuilderMinimum() { + final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal(); + return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal); + } + + private static void verifyPersistableBundleEncodeDecodeIsLossless( + TunnelModeChildSessionParams params) { + final PersistableBundle bundle = + TunnelModeChildSessionParamsUtils.toPersistableBundle(params); + final TunnelModeChildSessionParams result = + TunnelModeChildSessionParamsUtils.fromPersistableBundle(bundle); + + assertEquals(params, result); + } + + @Test + public void testMinimumParamsEncodeDecodeIsLossless() throws Exception { + final TunnelModeChildSessionParams sessionParams = createBuilderMinimum().build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } + + @Test + public void testSetTsEncodeDecodeIsLossless() throws Exception { + final IkeTrafficSelector tsInbound = + new IkeTrafficSelector( + 16, + 65520, + InetAddresses.parseNumericAddress("192.0.2.100"), + InetAddresses.parseNumericAddress("192.0.2.101")); + final IkeTrafficSelector tsOutbound = + new IkeTrafficSelector( + 32, + 256, + InetAddresses.parseNumericAddress("192.0.2.200"), + InetAddresses.parseNumericAddress("192.0.2.255")); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum() + .addInboundTrafficSelectors(tsInbound) + .addOutboundTrafficSelectors(tsOutbound) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } + + @Test + public void testSetLifetimesEncodeDecodeIsLossless() throws Exception { + final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(3L); + final int softLifetime = (int) TimeUnit.HOURS.toSeconds(1L); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } +} From e5172cd2de218c203fdb341589a35ec751cbf2af Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 22 Feb 2021 11:25:07 -0800 Subject: [PATCH 0096/1057] Support converting TunnelModeConfigRequest to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I9c53d4252edb0e8816c84d280b48c4725bd0edc8 --- .../TunnelModeChildSessionParamsUtils.java | 174 +++++++++++++++++- ...TunnelModeChildSessionParamsUtilsTest.java | 26 +++ 2 files changed, 197 insertions(+), 3 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java index 66a4330924..e62acac14b 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java @@ -16,17 +16,34 @@ package android.net.vcn.persistablebundleutils; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeTrafficSelector; 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 android.os.PersistableBundle; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -37,15 +54,99 @@ import java.util.Objects; */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class TunnelModeChildSessionParamsUtils { + private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName(); + private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY"; private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY"; private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; + private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; + + private static class ConfigRequest { + private static final int TYPE_IPV4_ADDRESS = 1; + private static final int TYPE_IPV6_ADDRESS = 2; + private static final int TYPE_IPV4_DNS = 3; + private static final int TYPE_IPV6_DNS = 4; + private static final int TYPE_IPV4_DHCP = 5; + private static final int TYPE_IPV4_NETMASK = 6; + + private static final String TYPE_KEY = "type"; + private static final String VALUE_KEY = "address"; + private static final String IP6_PREFIX_LEN = "ip6PrefixLen"; + + private static final int PREFIX_LEN_UNUSED = -1; + + public final int type; + public final int ip6PrefixLen; + + // Null when it is an empty request + @Nullable public final InetAddress address; + + ConfigRequest(TunnelModeChildConfigRequest config) { + int prefixLen = PREFIX_LEN_UNUSED; + + if (config instanceof ConfigRequestIpv4Address) { + type = TYPE_IPV4_ADDRESS; + address = ((ConfigRequestIpv4Address) config).getAddress(); + } else if (config instanceof ConfigRequestIpv6Address) { + type = TYPE_IPV6_ADDRESS; + address = ((ConfigRequestIpv6Address) config).getAddress(); + if (address != null) { + prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength(); + } + } else if (config instanceof ConfigRequestIpv4DnsServer) { + type = TYPE_IPV4_DNS; + address = null; + } else if (config instanceof ConfigRequestIpv6DnsServer) { + type = TYPE_IPV6_DNS; + address = null; + } else if (config instanceof ConfigRequestIpv4DhcpServer) { + type = TYPE_IPV4_DHCP; + address = null; + } else if (config instanceof ConfigRequestIpv4Netmask) { + type = TYPE_IPV4_NETMASK; + address = null; + } else { + throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); + } + + ip6PrefixLen = prefixLen; + } + + ConfigRequest(PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + type = in.getInt(TYPE_KEY); + ip6PrefixLen = in.getInt(IP6_PREFIX_LEN); + + String addressStr = in.getString(VALUE_KEY); + if (addressStr == null) { + address = null; + } else { + address = InetAddresses.parseNumericAddress(addressStr); + } + } + + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(TYPE_KEY, type); + result.putInt(IP6_PREFIX_LEN, ip6PrefixLen); + + if (address != null) { + result.putString(VALUE_KEY, address.getHostAddress()); + } + + return result; + } + } /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */ @NonNull - public static PersistableBundle toPersistableBundle(TunnelModeChildSessionParams params) { + public static PersistableBundle toPersistableBundle( + @NonNull TunnelModeChildSessionParams params) { final PersistableBundle result = new PersistableBundle(); final PersistableBundle saProposalBundle = @@ -68,7 +169,13 @@ public final class TunnelModeChildSessionParamsUtils { result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); - // TODO: b/163604823 Support serializing configuration requests. + final List reqList = new ArrayList<>(); + for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) { + reqList.add(new ConfigRequest(req)); + } + final PersistableBundle configReqListBundle = + PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); + result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); return result; } @@ -109,8 +216,69 @@ public final class TunnelModeChildSessionParamsUtils { builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); + final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); + Objects.requireNonNull(configReqListBundle, "Config request list was null"); + final List reqList = + PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); - // TODO: b/163604823 Support deserializing configuration requests. + boolean hasIpv4AddressReq = false; + boolean hasIpv4NetmaskReq = false; + for (ConfigRequest req : reqList) { + switch (req.type) { + case ConfigRequest.TYPE_IPV4_ADDRESS: + hasIpv4AddressReq = true; + if (req.address == null) { + builder.addInternalAddressRequest(AF_INET); + } else { + builder.addInternalAddressRequest((Inet4Address) req.address); + } + break; + case ConfigRequest.TYPE_IPV6_ADDRESS: + if (req.address == null) { + builder.addInternalAddressRequest(AF_INET6); + } else { + builder.addInternalAddressRequest( + (Inet6Address) req.address, req.ip6PrefixLen); + } + break; + case ConfigRequest.TYPE_IPV4_NETMASK: + // Do not need to set netmask because it will be automatically set by the + // builder when an IPv4 internal address request is set. + hasIpv4NetmaskReq = true; + break; + case ConfigRequest.TYPE_IPV4_DNS: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported"); + } + builder.addInternalDnsServerRequest(AF_INET); + break; + case ConfigRequest.TYPE_IPV6_DNS: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported"); + } + builder.addInternalDnsServerRequest(AF_INET6); + break; + case ConfigRequest.TYPE_IPV4_DHCP: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported"); + } + builder.addInternalDhcpServerRequest(AF_INET); + break; + default: + throw new IllegalArgumentException( + "Unrecognized config request type: " + req.type); + } + } + + if (hasIpv4AddressReq != hasIpv4NetmaskReq) { + Log.w( + TAG, + String.format( + "Expect IPv4 address request and IPv4 netmask request either both" + + " exist or both absent, but found hasIpv4AddressReq exists? %b," + + " hasIpv4AddressReq exists? %b, ", + hasIpv4AddressReq, hasIpv4NetmaskReq)); + } return builder.build(); } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java index b757aa2b4e..b3cd0ab805 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java @@ -16,6 +16,9 @@ package android.net.vcn.persistablebundleutils; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static org.junit.Assert.assertEquals; import android.net.InetAddresses; @@ -30,6 +33,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -88,4 +93,25 @@ public class TunnelModeChildSessionParamsUtilsTest { createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); } + + @Test + public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception { + final int ipv6PrefixLen = 64; + final Inet4Address ipv4Address = + (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); + final Inet6Address ipv6Address = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum() + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(ipv4Address) + .addInternalAddressRequest(ipv6Address, ipv6PrefixLen) + .addInternalDnsServerRequest(AF_INET) + .addInternalDnsServerRequest(AF_INET6) + .addInternalDhcpServerRequest(AF_INET) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } } From ade4ea3ddac73ad4bf54f1472b7f46866f13c51e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 22 Feb 2021 17:28:13 -0800 Subject: [PATCH 0097/1057] Support converting EapSessionConfig to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: Iac7077b4ca37dfc07055aac5b3a8118610a27999 --- .../EapSessionConfigUtils.java | 112 ++++++++++++++++++ .../EapSessionConfigUtilsTest.java | 57 +++++++++ 2 files changed, 169 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java new file mode 100644 index 0000000000..e0047d08a8 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java @@ -0,0 +1,112 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.eap.EapSessionConfig; +import android.net.eap.EapSessionConfig.EapMethodConfig; +import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.Objects; + +/** + * Provides utility methods to convert EapSessionConfig to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class EapSessionConfigUtils { + private static final String EAP_ID_KEY = "EAP_ID_KEY"; + private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY"; + + /** Serializes an EapSessionConfig to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) { + final PersistableBundle result = new PersistableBundle(); + + result.putPersistableBundle( + EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity())); + + if (config.getEapMsChapV2Config() != null) { + result.putPersistableBundle( + EAP_MSCHAP_V2_CONFIG_KEY, + EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config())); + } + + // TODO: Handle other EAP methods: EAP-SIM, EAP-AKA, EAP-AKA', EAP-TTLS. + + return result; + } + + /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */ + @NonNull + public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final EapSessionConfig.Builder builder = new EapSessionConfig.Builder(); + + final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY); + Objects.requireNonNull(eapIdBundle, "EAP ID was null"); + builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle)); + + final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY); + if (msChapV2Bundle != null) { + EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder); + } + + // TODO: Handle other EAP methods: EAP-SIM, EAP-AKA, EAP-AKA', EAP-TTLS. + return builder.build(); + } + + private static class EapMethodConfigUtils { + private static final String METHOD_TYPE = "METHOD_TYPE"; + + /** Serializes an EapMethodConfig to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) { + final PersistableBundle result = new PersistableBundle(); + result.putInt(METHOD_TYPE, config.getMethodType()); + return result; + } + } + + private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils { + private static final String USERNAME_KEY = "USERNAME_KEY"; + private static final String PASSWORD_KEY = "PASSWORD_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + result.putString(USERNAME_KEY, config.getUsername()); + result.putString(PASSWORD_KEY, config.getPassword()); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY)); + } + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java new file mode 100644 index 0000000000..537202bc72 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java @@ -0,0 +1,57 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.eap.EapSessionConfig; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.charset.StandardCharsets; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class EapSessionConfigUtilsTest { + private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII); + private static final String USERNAME = "username"; + private static final String PASSWORD = "password"; + + private EapSessionConfig.Builder createBuilderWithId() { + return new EapSessionConfig.Builder().setEapIdentity(EAP_ID); + } + + private static void verifyPersistableBundleEncodeDecodeIsLossless(EapSessionConfig config) { + final PersistableBundle bundle = EapSessionConfigUtils.toPersistableBundle(config); + final EapSessionConfig resultConfig = EapSessionConfigUtils.fromPersistableBundle(bundle); + + assertEquals(config, resultConfig); + } + + @Test + public void testSetEapMsChapV2EncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapMsChapV2Config(USERNAME, PASSWORD).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } +} From 3e6af4f06ccb538052cd0c14d1df42e10d517987 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Feb 2021 16:13:49 -0800 Subject: [PATCH 0098/1057] Support converting EAP-SIM, AKA and AKA' to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: Ib4a0ed69b57df10c5ede9524d0b03f4f03d68919 --- .../EapSessionConfigUtils.java | 109 +++++++++++++++++- .../EapSessionConfigUtilsTest.java | 32 +++++ 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java index e0047d08a8..b2b9862072 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java @@ -16,12 +16,17 @@ package android.net.vcn.persistablebundleutils; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.eap.EapSessionConfig; +import android.net.eap.EapSessionConfig.EapAkaConfig; +import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; import android.net.eap.EapSessionConfig.EapMethodConfig; import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.net.eap.EapSessionConfig.EapSimConfig; +import android.net.eap.EapSessionConfig.EapUiccConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; @@ -37,7 +42,10 @@ import java.util.Objects; @VisibleForTesting(visibility = Visibility.PRIVATE) public final class EapSessionConfigUtils { private static final String EAP_ID_KEY = "EAP_ID_KEY"; + private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY"; + private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY"; private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY"; + private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY"; /** Serializes an EapSessionConfig to a PersistableBundle. */ @NonNull @@ -47,13 +55,31 @@ public final class EapSessionConfigUtils { result.putPersistableBundle( EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity())); + if (config.getEapSimConfig() != null) { + result.putPersistableBundle( + EAP_SIM_CONFIG_KEY, + EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig())); + } + + if (config.getEapAkaConfig() != null) { + result.putPersistableBundle( + EAP_AKA_CONFIG_KEY, + EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig())); + } + if (config.getEapMsChapV2Config() != null) { result.putPersistableBundle( EAP_MSCHAP_V2_CONFIG_KEY, EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config())); } - // TODO: Handle other EAP methods: EAP-SIM, EAP-AKA, EAP-AKA', EAP-TTLS. + if (config.getEapAkaPrimeConfig() != null) { + result.putPersistableBundle( + EAP_AKA_PRIME_CONFIG_KEY, + EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig())); + } + + // TODO: Handle EAP-TTLS. return result; } @@ -69,12 +95,27 @@ public final class EapSessionConfigUtils { Objects.requireNonNull(eapIdBundle, "EAP ID was null"); builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle)); + final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY); + if (simBundle != null) { + EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder); + } + + final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY); + if (akaBundle != null) { + EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder); + } + final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY); if (msChapV2Bundle != null) { EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder); } - // TODO: Handle other EAP methods: EAP-SIM, EAP-AKA, EAP-AKA', EAP-TTLS. + final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY); + if (akaPrimeBundle != null) { + EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder); + } + + // TODO: Handle EAP-TTLS. return builder.build(); } @@ -90,6 +131,70 @@ public final class EapSessionConfigUtils { } } + private static class EapUiccConfigUtils extends EapMethodConfigUtils { + static final String SUB_ID_KEY = "SUB_ID_KEY"; + static final String APP_TYPE_KEY = "APP_TYPE_KEY"; + + @NonNull + protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + result.putInt(SUB_ID_KEY, config.getSubId()); + result.putInt(APP_TYPE_KEY, config.getAppType()); + + return result; + } + } + + private static final class EapSimConfigUtils extends EapUiccConfigUtils { + @NonNull + public static PersistableBundle toPersistableBundle(EapSimConfig config) { + return EapUiccConfigUtils.toPersistableBundle(config); + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); + } + } + + private static class EapAkaConfigUtils extends EapUiccConfigUtils { + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) { + return EapUiccConfigUtils.toPersistableBundle(config); + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); + } + } + + private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils { + private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY"; + private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) { + final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config); + result.putString(NETWORK_NAME_KEY, config.getNetworkName()); + result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames()); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapAkaPrimeConfig( + in.getInt(SUB_ID_KEY), + in.getInt(APP_TYPE_KEY), + in.getString(NETWORK_NAME_KEY), + in.getBoolean(ALL_MISMATCHED_NETWORK_KEY)); + } + } + private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils { private static final String USERNAME_KEY = "USERNAME_KEY"; private static final String PASSWORD_KEY = "PASSWORD_KEY"; diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java index 537202bc72..860d723818 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java @@ -16,6 +16,8 @@ package android.net.vcn.persistablebundleutils; +import static android.telephony.TelephonyManager.APPTYPE_USIM; + import static org.junit.Assert.assertEquals; import android.net.eap.EapSessionConfig; @@ -35,6 +37,9 @@ public class EapSessionConfigUtilsTest { private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII); private static final String USERNAME = "username"; private static final String PASSWORD = "password"; + private static final int SUB_ID = 1; + private static final String NETWORK_NAME = "android.net"; + private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true; private EapSessionConfig.Builder createBuilderWithId() { return new EapSessionConfig.Builder().setEapIdentity(EAP_ID); @@ -54,4 +59,31 @@ public class EapSessionConfigUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(config); } + + @Test + public void testSetEapSimEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapSimConfig(SUB_ID, APPTYPE_USIM).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapAkaEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapAkaConfig(SUB_ID, APPTYPE_USIM).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapAkaPrimeEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId() + .setEapAkaPrimeConfig( + SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES) + .build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } } From 8e1661ba6f7bfd77b9182ca74adfa6d21d0264fd Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Feb 2021 16:40:18 -0800 Subject: [PATCH 0099/1057] Support converting EAP-TTLS to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I1e338d9c8940636b38f4725787de30fbbc1323ec --- .../vcn/persistablebundleutils/CertUtils.java | 46 +++++++++++++ .../EapSessionConfigUtils.java | 65 ++++++++++++++++++- Vcn/tests/unit/assets/self-signed-ca.pem | 20 ++++++ .../EapSessionConfigUtilsTest.java | 24 +++++++ 4 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java create mode 100644 Vcn/tests/unit/assets/self-signed-ca.pem diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java new file mode 100644 index 0000000000..b6036b4a6f --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java @@ -0,0 +1,46 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Objects; + +/** + * CertUtils provides utility methods for constructing Certificate. + * + * @hide + */ +public class CertUtils { + private static final String CERT_TYPE_X509 = "X.509"; + + /** Decodes an ASN.1 DER encoded Certificate */ + public static X509Certificate certificateFromByteArray(byte[] derEncoded) { + Objects.requireNonNull(derEncoded, "derEncoded is null"); + + try { + CertificateFactory certFactory = CertificateFactory.getInstance(CERT_TYPE_X509); + InputStream in = new ByteArrayInputStream(derEncoded); + return (X509Certificate) certFactory.generateCertificate(in); + } catch (CertificateException e) { + throw new IllegalArgumentException("Fail to decode certificate", e); + } + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java index b2b9862072..853a52da76 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java @@ -26,12 +26,15 @@ import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; import android.net.eap.EapSessionConfig.EapMethodConfig; import android.net.eap.EapSessionConfig.EapMsChapV2Config; import android.net.eap.EapSessionConfig.EapSimConfig; +import android.net.eap.EapSessionConfig.EapTtlsConfig; import android.net.eap.EapSessionConfig.EapUiccConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; import java.util.Objects; /** @@ -43,6 +46,7 @@ import java.util.Objects; public final class EapSessionConfigUtils { private static final String EAP_ID_KEY = "EAP_ID_KEY"; private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY"; + private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY"; private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY"; private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY"; private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY"; @@ -61,6 +65,12 @@ public final class EapSessionConfigUtils { EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig())); } + if (config.getEapTtlsConfig() != null) { + result.putPersistableBundle( + EAP_TTLS_CONFIG_KEY, + EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig())); + } + if (config.getEapAkaConfig() != null) { result.putPersistableBundle( EAP_AKA_CONFIG_KEY, @@ -79,8 +89,6 @@ public final class EapSessionConfigUtils { EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig())); } - // TODO: Handle EAP-TTLS. - return result; } @@ -100,6 +108,11 @@ public final class EapSessionConfigUtils { EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder); } + final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY); + if (ttlsBundle != null) { + EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder); + } + final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY); if (akaBundle != null) { EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder); @@ -115,7 +128,6 @@ public final class EapSessionConfigUtils { EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder); } - // TODO: Handle EAP-TTLS. return builder.build(); } @@ -214,4 +226,51 @@ public final class EapSessionConfigUtils { builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY)); } } + + private static final class EapTtlsConfigUtils extends EapMethodConfigUtils { + private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; + private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + try { + if (config.getServerCaCert() != null) { + final PersistableBundle caBundle = + PersistableBundleUtils.fromByteArray( + config.getServerCaCert().getEncoded()); + result.putPersistableBundle(TRUST_CERT_KEY, caBundle); + } + } catch (CertificateEncodingException e) { + throw new IllegalStateException("Fail to encode the certificate"); + } + + result.putPersistableBundle( + EAP_SESSION_CONFIG_KEY, + EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig())); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY); + X509Certificate caCert = null; + if (caBundle != null) { + caCert = + CertUtils.certificateFromByteArray( + PersistableBundleUtils.toByteArray(caBundle)); + } + + final PersistableBundle eapSessionConfigBundle = + in.getPersistableBundle(EAP_SESSION_CONFIG_KEY); + Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null"); + final EapSessionConfig eapSessionConfig = + EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle); + + builder.setEapTtlsConfig(caCert, eapSessionConfig); + } + } } diff --git a/Vcn/tests/unit/assets/self-signed-ca.pem b/Vcn/tests/unit/assets/self-signed-ca.pem new file mode 100644 index 0000000000..5135ea7077 --- /dev/null +++ b/Vcn/tests/unit/assets/self-signed-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p +ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG +EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk +Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy +Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR +Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp +99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ +1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc +g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5 +JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB +AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb +QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05 +yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6 +Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P +t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8 +u4r44fj4/9W0Zeooav5Yoh1q +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java index 860d723818..bc8e9d3200 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java @@ -23,13 +23,17 @@ import static org.junit.Assert.assertEquals; import android.net.eap.EapSessionConfig; import android.os.PersistableBundle; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; @RunWith(AndroidJUnit4.class) @SmallTest @@ -86,4 +90,24 @@ public class EapSessionConfigUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(config); } + + @Test + public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception { + final InputStream inputStream = + InstrumentationRegistry.getContext() + .getResources() + .getAssets() + .open("self-signed-ca.pem"); + final CertificateFactory factory = CertificateFactory.getInstance("X.509"); + final X509Certificate trustedCa = + (X509Certificate) factory.generateCertificate(inputStream); + + final EapSessionConfig innerConfig = + new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build(); + + final EapSessionConfig config = + new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } } From 3b9ed283c22747e34e4df54b12193c377b5cde96 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Feb 2021 22:39:32 -0800 Subject: [PATCH 0100/1057] Support converting IKE ID to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I65dbc509f23334df2f22d6c4658e31acc9bef787 --- .../IkeIdentificationUtils.java | 143 ++++++++++++++++++ .../IkeIdentificationUtilsTest.java | 87 +++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java new file mode 100644 index 0000000000..6acb34ebb7 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java @@ -0,0 +1,143 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +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 android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.util.Objects; + +import javax.security.auth.x500.X500Principal; + +/** + * Abstract utility class to convert IkeIdentification to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeIdentificationUtils { + private static final String ID_TYPE_KEY = "ID_TYPE_KEY"; + + private static final String DER_ASN1_DN_KEY = "DER_ASN1_DN_KEY"; + private static final String FQDN_KEY = "FQDN_KEY"; + private static final String KEY_ID_KEY = "KEY_ID_KEY"; + private static final String IP4_ADDRESS_KEY = "IP4_ADDRESS_KEY"; + private static final String IP6_ADDRESS_KEY = "IP6_ADDRESS_KEY"; + private static final String RFC822_ADDRESS_KEY = "RFC822_ADDRESS_KEY"; + + private static final int ID_TYPE_DER_ASN1_DN = 1; + private static final int ID_TYPE_FQDN = 2; + private static final int ID_TYPE_IPV4_ADDR = 3; + private static final int ID_TYPE_IPV6_ADDR = 4; + private static final int ID_TYPE_KEY_ID = 5; + private static final int ID_TYPE_RFC822_ADDR = 6; + + /** Serializes an IkeIdentification to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull IkeIdentification ikeId) { + if (ikeId instanceof IkeDerAsn1DnIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_DER_ASN1_DN); + IkeDerAsn1DnIdentification id = (IkeDerAsn1DnIdentification) ikeId; + result.putPersistableBundle( + DER_ASN1_DN_KEY, + PersistableBundleUtils.fromByteArray(id.derAsn1Dn.getEncoded())); + return result; + } else if (ikeId instanceof IkeFqdnIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_FQDN); + IkeFqdnIdentification id = (IkeFqdnIdentification) ikeId; + result.putString(FQDN_KEY, id.fqdn); + return result; + } else if (ikeId instanceof IkeIpv4AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV4_ADDR); + IkeIpv4AddrIdentification id = (IkeIpv4AddrIdentification) ikeId; + result.putString(IP4_ADDRESS_KEY, id.ipv4Address.getHostAddress()); + return result; + } else if (ikeId instanceof IkeIpv6AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV6_ADDR); + IkeIpv6AddrIdentification id = (IkeIpv6AddrIdentification) ikeId; + result.putString(IP6_ADDRESS_KEY, id.ipv6Address.getHostAddress()); + return result; + } else if (ikeId instanceof IkeKeyIdIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_KEY_ID); + IkeKeyIdIdentification id = (IkeKeyIdIdentification) ikeId; + result.putPersistableBundle(KEY_ID_KEY, PersistableBundleUtils.fromByteArray(id.keyId)); + return result; + } else if (ikeId instanceof IkeRfc822AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_RFC822_ADDR); + IkeRfc822AddrIdentification id = (IkeRfc822AddrIdentification) ikeId; + result.putString(RFC822_ADDRESS_KEY, id.rfc822Name); + return result; + } else { + throw new IllegalStateException("Unrecognized IkeIdentification subclass"); + } + } + + private static PersistableBundle createPersistableBundle(int idType) { + final PersistableBundle result = new PersistableBundle(); + result.putInt(ID_TYPE_KEY, idType); + return result; + } + + /** Constructs an IkeIdentification by deserializing a PersistableBundle. */ + @NonNull + public static IkeIdentification fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + int idType = in.getInt(ID_TYPE_KEY); + switch (idType) { + case ID_TYPE_DER_ASN1_DN: + final PersistableBundle dnBundle = in.getPersistableBundle(DER_ASN1_DN_KEY); + Objects.requireNonNull(dnBundle, "ASN1 DN was null"); + return new IkeDerAsn1DnIdentification( + new X500Principal(PersistableBundleUtils.toByteArray(dnBundle))); + case ID_TYPE_FQDN: + return new IkeFqdnIdentification(in.getString(FQDN_KEY)); + case ID_TYPE_IPV4_ADDR: + final String v4AddressStr = in.getString(IP4_ADDRESS_KEY); + Objects.requireNonNull(v4AddressStr, "IPv4 address was null"); + return new IkeIpv4AddrIdentification( + (Inet4Address) InetAddresses.parseNumericAddress(v4AddressStr)); + case ID_TYPE_IPV6_ADDR: + final String v6AddressStr = in.getString(IP6_ADDRESS_KEY); + Objects.requireNonNull(v6AddressStr, "IPv6 address was null"); + return new IkeIpv6AddrIdentification( + (Inet6Address) InetAddresses.parseNumericAddress(v6AddressStr)); + case ID_TYPE_KEY_ID: + final PersistableBundle keyIdBundle = in.getPersistableBundle(KEY_ID_KEY); + Objects.requireNonNull(in, "Key ID was null"); + return new IkeKeyIdIdentification(PersistableBundleUtils.toByteArray(keyIdBundle)); + case ID_TYPE_RFC822_ADDR: + return new IkeRfc822AddrIdentification(in.getString(RFC822_ADDRESS_KEY)); + default: + throw new IllegalStateException("Unrecognized IKE ID type: " + idType); + } + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java new file mode 100644 index 0000000000..4f3930f9b5 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java @@ -0,0 +1,87 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +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 android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IkeIdentificationUtilsTest { + private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) { + final PersistableBundle bundle = IkeIdentificationUtils.toPersistableBundle(id); + final IkeIdentification result = IkeIdentificationUtils.fromPersistableBundle(bundle); + + assertEquals(result, id); + } + + @Test + public void testPersistableBundleEncodeDecodeIpv4AddressId() throws Exception { + final Inet4Address ipv4Address = (Inet4Address) InetAddress.getByName("192.0.2.100"); + verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv4AddrIdentification(ipv4Address)); + } + + @Test + public void testPersistableBundleEncodeDecodeIpv6AddressId() throws Exception { + final Inet6Address ipv6Address = (Inet6Address) InetAddress.getByName("2001:db8:2::100"); + verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv6AddrIdentification(ipv6Address)); + } + + @Test + public void testPersistableBundleEncodeDecodeRfc822AddrId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless(new IkeFqdnIdentification("ike.android.net")); + } + + @Test + public void testPersistableBundleEncodeDecodeFqdnId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeRfc822AddrIdentification("androidike@example.com")); + } + + @Test + public void testPersistableBundleEncodeDecodeKeyId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeKeyIdIdentification("androidIkeKeyId".getBytes())); + } + + @Test + public void testPersistableBundleEncodeDecodeDerAsn1DnId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeDerAsn1DnIdentification( + new X500Principal("CN=small.server.test.android.net, O=Android, C=US"))); + } +} From 0d0121ba24a0fe277f2132ca852b7c870fa9b7b3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 10 Feb 2021 15:44:26 -0800 Subject: [PATCH 0101/1057] Allow NETWORK_LOST disconnections to retry This change adds the ability for disconnection requests to specify whether the full VcnGatewayConnection should be torn down. This is useful in cases where the cause is an ephemeral failure, and can be restarted at some later point (eg an underlying network appears, or a new NetworkRequest is filed that brings the VCN up.) Bug: 179944275 Test: atest FrameworksVcnTests Change-Id: Id1813bcbbb80541be97cc383ea9d1fe08554b7ae --- .../server/vcn/VcnGatewayConnection.java | 76 ++++++++++--------- ...cnGatewayConnectionConnectedStateTest.java | 18 +++++ ...nGatewayConnectionConnectingStateTest.java | 20 +++++ ...atewayConnectionDisconnectedStateTest.java | 13 ++++ ...tewayConnectionDisconnectingStateTest.java | 12 +++ ...atewayConnectionRetryTimeoutStateTest.java | 21 +++++ 6 files changed, 126 insertions(+), 34 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 06748a3aa2..a2f4782ec1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -168,6 +168,8 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: "; private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; + private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED = + "NetworkAgent was unwanted"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ALL = Integer.MIN_VALUE; @@ -379,13 +381,16 @@ public class VcnGatewayConnection extends StateMachine { /** The reason why the disconnect was requested. */ @NonNull public final String reason; - EventDisconnectRequestedInfo(@NonNull String reason) { + public final boolean shouldTeardown; + + EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldTeardown) { this.reason = Objects.requireNonNull(reason); + this.shouldTeardown = shouldTeardown; } @Override public int hashCode() { - return Objects.hash(reason); + return Objects.hash(reason, shouldTeardown); } @Override @@ -395,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine { } final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; - return reason.equals(rhs.reason); + return reason.equals(rhs.reason) && shouldTeardown == rhs.shouldTeardown; } } @@ -622,10 +627,8 @@ public class VcnGatewayConnection extends StateMachine { *

    Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_TEARDOWN, true /* shouldTeardown */); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -892,7 +895,8 @@ public class VcnGatewayConnection extends StateMachine { TOKEN_ALL, 0 /* arg2 */, new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, + false /* shouldTeardown */)); mDisconnectRequestAlarm = createScheduledAlarm( DISCONNECT_REQUEST_ALARM, @@ -909,7 +913,8 @@ public class VcnGatewayConnection extends StateMachine { // Cancel any existing disconnect due to previous loss of underlying network removeEqualMessages( EVENT_DISCONNECT_REQUESTED, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldTeardown */)); } private void setRetryTimeoutAlarm(long delay) { @@ -1041,11 +1046,8 @@ public class VcnGatewayConnection extends StateMachine { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } } @@ -1083,11 +1085,8 @@ public class VcnGatewayConnection extends StateMachine { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } // Attempt to release the WakeLock - only possible if the Handler queue is empty @@ -1104,11 +1103,8 @@ public class VcnGatewayConnection extends StateMachine { exitState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } } @@ -1141,11 +1137,11 @@ public class VcnGatewayConnection extends StateMachine { } } - protected void handleDisconnectRequested(String msg) { + protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.v(TAG, "Tearing down. Cause: " + msg); - mIsRunning = false; + Slog.v(TAG, "Tearing down. Cause: " + info.reason); + mIsRunning = !info.shouldTeardown; teardownNetwork(); @@ -1200,9 +1196,11 @@ public class VcnGatewayConnection extends StateMachine { } break; case EVENT_DISCONNECT_REQUESTED: - mIsRunning = false; + if (((EventDisconnectRequestedInfo) msg.obj).shouldTeardown) { + mIsRunning = false; - quitNow(); + quitNow(); + } break; default: logUnhandledMessage(msg); @@ -1284,10 +1282,11 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: + EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); + mIsRunning = !info.shouldTeardown; teardownNetwork(); - String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; - if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { + if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { // TODO(b/180526152): notify VcnStatusCallback for Network loss // Will trigger EVENT_SESSION_CLOSED immediately. @@ -1391,7 +1390,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectedState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1438,6 +1437,7 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.getVcnNetworkProvider()) { @Override public void unwanted() { + Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } @@ -1577,7 +1577,7 @@ public class VcnGatewayConnection extends StateMachine { setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1682,7 +1682,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectingState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1924,6 +1924,14 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = session; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldTeardown) { + sendMessageAndAcquireWakeLock( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo(reason, shouldTeardown)); + } + private IkeSessionParams buildIkeParams() { // TODO: Implement this once IkeSessionParams is persisted return null; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 69c21b9679..12c61cec87 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -290,4 +290,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 17ae19e086..0f94426e12 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -19,6 +19,8 @@ package com.android.server.vcn; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -111,4 +113,22 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 9ea641f52e..90810b6cd4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -21,7 +21,9 @@ import static android.net.IpSecManager.IpSecTunnelInterface; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -101,5 +103,16 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + // No safe mode timer changes expected. } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 7385204993..c57237c2f7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -18,6 +18,8 @@ package com.android.server.vcn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -79,10 +81,20 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); + assertFalse(mGatewayConnection.isRunning()); } @Test public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 5b0850b03f..1e8e7a0b77 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -17,6 +17,9 @@ package com.android.server.vcn; 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 androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -96,4 +99,22 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); } + + @Test + public void testTeardownDisconnectRequest() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } From b17c5711fb3cd9bcee69a0451e67037106705cdc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 10 Feb 2021 15:55:53 -0800 Subject: [PATCH 0102/1057] Notify Vcn of VcnGatewayConnection quits This change updates the Vcn when any GatewayConnection StateMachine quits, removing it from the map of active GatewayConnections, and triggering a re-evaluation of all existing NetworkRequests. This may (in the event of a updated policy) result in an immediate restart. Bug: 179944275 Test: atest FrameworksVcnTests Change-Id: I72abf1e270a772760a17a03173d5a110e15bd01d --- .../src/com/android/server/vcn/Vcn.java | 44 ++++++++++- .../server/vcn/VcnGatewayConnection.java | 2 + .../server/vcn/VcnNetworkProvider.java | 12 ++- ...atewayConnectionDisconnectedStateTest.java | 3 + .../java/com/android/server/vcn/VcnTest.java | 73 ++++++++++++++++--- 5 files changed, 117 insertions(+), 17 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 6ad30b5442..9d39c67d27 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; + import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -84,6 +86,13 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2; + /** + * A GatewayConnection owned by this VCN quit. + * + * @param obj VcnGatewayConnectionConfig + */ + private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; @@ -208,6 +217,9 @@ public class Vcn extends Handler { case MSG_EVENT_SUBSCRIPTIONS_CHANGED: handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); break; + case MSG_EVENT_GATEWAY_CONNECTION_QUIT: + handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; @@ -263,7 +275,7 @@ public class Vcn extends Handler { // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { - if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { if (VDBG) { Slog.v( getLogTag(), @@ -278,7 +290,7 @@ public class Vcn extends Handler { // up for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { - if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { Slog.v( getLogTag(), "Bringing up new VcnGatewayConnection for request " + request.requestId); @@ -289,12 +301,21 @@ public class Vcn extends Handler { mSubscriptionGroup, mLastSnapshot, gatewayConnectionConfig, - new VcnGatewayStatusCallbackImpl()); + new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig)); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } } + private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { + Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); + mVcnGatewayConnections.remove(config); + + // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied + // start a new GatewayConnection) + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } + private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; @@ -305,9 +326,10 @@ public class Vcn extends Handler { } } - private boolean requestSatisfiedByGatewayConnectionConfig( + private boolean isRequestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); + builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); for (int cap : config.getAllExposedCapabilities()) { builder.addCapability(cap); } @@ -339,9 +361,23 @@ public class Vcn extends Handler { @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage); + + /** Called by a VcnGatewayConnection to indicate that it has fully torn down. */ + void onQuit(); } private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { + public final VcnGatewayConnectionConfig mGatewayConnectionConfig; + + VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) { + mGatewayConnectionConfig = gatewayConnectionConfig; + } + + @Override + public void onQuit() { + sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig)); + } + @Override public void onEnteredSafeMode() { sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index a2f4782ec1..b422b8f4a5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -649,6 +649,8 @@ public class VcnGatewayConnection extends StateMachine { cancelSafeModeAlarm(); mUnderlyingNetworkTracker.teardown(); + + mGatewayStatusCallback.onQuit(); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index bfeec011a2..a909695991 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -67,9 +67,7 @@ public class VcnNetworkProvider extends NetworkProvider { mListeners.add(listener); // Send listener all cached requests - for (NetworkRequestEntry entry : mRequests.values()) { - notifyListenerForEvent(listener, entry); - } + resendAllRequests(listener); } /** Unregisters the specified listener from receiving future NetworkRequests. */ @@ -78,6 +76,14 @@ public class VcnNetworkProvider extends NetworkProvider { mListeners.remove(listener); } + /** Sends all cached NetworkRequest(s) to the specified listener. */ + @VisibleForTesting(visibility = Visibility.PACKAGE) + public void resendAllRequests(@NonNull NetworkRequestListener listener) { + for (NetworkRequestEntry entry : mRequests.values()) { + notifyListenerForEvent(listener, entry); + } + } + private void notifyListenerForEvent( @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 90810b6cd4..a978c335d5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.net.IpSecManager; @@ -104,6 +105,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); assertFalse(mGatewayConnection.isRunning()); + verify(mGatewayStatusCallback).onQuit(); } @Test @@ -113,6 +115,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isRunning()); + verify(mGatewayStatusCallback, never()).onQuit(); // No safe mode timer changes expected. } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 9d33682712..3dd710afed 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -16,6 +16,10 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; @@ -33,6 +37,7 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -51,6 +56,11 @@ public class VcnTest { private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int NETWORK_SCORE = 0; private static final int PROVIDER_ID = 5; + private static final int[][] TEST_CAPS = + new int[][] { + new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS}, + new int[] {NET_CAPABILITY_DUN} + }; private Context mContext; private VcnContext mVcnContext; @@ -91,13 +101,12 @@ public class VcnTest { mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext); - for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + for (final int[] caps : TEST_CAPS) { configBuilder.addGatewayConnectionConfig( - VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability)); + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps)); } - configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig()); - mConfig = configBuilder.build(); + mConfig = configBuilder.build(); mVcn = new Vcn( mVcnContext, @@ -130,8 +139,7 @@ public class VcnTest { @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - startVcnGatewayWithCapabilities( - requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS); + startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); final Set gatewayConnections = mVcn.getVcnGatewayConnections(); assertFalse(gatewayConnections.isEmpty()); @@ -153,10 +161,19 @@ public class VcnTest { for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { startVcnGatewayWithCapabilities(requestListener, capability); } + } - // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp. - // Expect one VcnGatewayConnection per capability. - final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length; + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { + for (final int[] caps : TEST_CAPS) { + startVcnGatewayWithCapabilities(requestListener, caps); + } + } + + public Set startGatewaysAndGetGatewayConnections( + NetworkRequestListener requestListener) { + triggerVcnRequestListeners(requestListener); + + final int numExpectedGateways = TEST_CAPS.length; final Set gatewayConnections = mVcn.getVcnGatewayConnections(); assertEquals(numExpectedGateways, gatewayConnections.size()); @@ -168,7 +185,16 @@ public class VcnTest { any(), mGatewayStatusCallbackCaptor.capture()); - // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down + return gatewayConnections; + } + + @Test + public void testGatewayEnteringSafemodeNotifiesVcn() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set gatewayConnections = + startGatewaysAndGetGatewayConnections(requestListener); + + // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down // all Gateways final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); statusCallback.onEnteredSafeMode(); @@ -181,4 +207,31 @@ public class VcnTest { verify(mVcnNetworkProvider).unregisterListener(requestListener); verify(mVcnCallback).onEnteredSafeMode(); } + + @Test + public void testGatewayQuit() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onQuit(); + mTestLooper.dispatchAll(); + + // Verify that the VCN requests the networkRequests be resent + assertEquals(1, mVcn.getVcnGatewayConnections().size()); + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + + // Verify that the VcnGatewayConnection is restarted + triggerVcnRequestListeners(requestListener); + mTestLooper.dispatchAll(); + assertEquals(2, mVcn.getVcnGatewayConnections().size()); + verify(mDeps, times(gatewayConnections.size() + 1)) + .newVcnGatewayConnection( + eq(mVcnContext), + eq(TEST_SUB_GROUP), + eq(mSubscriptionSnapshot), + any(), + mGatewayStatusCallbackCaptor.capture()); + } } From b23292ff42bd432588026f98611d2dcc439bfd9c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 1 Mar 2021 14:15:58 -0800 Subject: [PATCH 0103/1057] Rename isRunning to isQuitting, and flip all booleans Per code reviews, this may increase readability Bug: 179944275 Test: atest FrameworksVcnTests Change-Id: I5bc0fe946b8da870a8e89f6e07b1d1ade5865710 --- .../server/vcn/UnderlyingNetworkTracker.java | 6 +- .../server/vcn/VcnGatewayConnection.java | 59 ++++++++++--------- ...cnGatewayConnectionConnectedStateTest.java | 4 +- ...nGatewayConnectionConnectingStateTest.java | 4 +- ...atewayConnectionDisconnectedStateTest.java | 8 +-- ...tewayConnectionDisconnectingStateTest.java | 4 +- ...atewayConnectionRetryTimeoutStateTest.java | 4 +- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index b6ddd93af3..b2db9f5af0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -65,7 +65,7 @@ public class UnderlyingNetworkTracker { @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; - private boolean mIsRunning = true; + private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; @@ -151,7 +151,7 @@ public class UnderlyingNetworkTracker { mVcnContext.ensureRunningOnLooperThread(); // Don't bother re-filing NetworkRequests if this Tracker has been torn down. - if (!mIsRunning) { + if (mIsQuitting) { return; } @@ -205,7 +205,7 @@ public class UnderlyingNetworkTracker { } mCellBringupCallbacks.clear(); - mIsRunning = false; + mIsQuitting = true; } /** Returns whether the currently selected Network matches the given network. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index b422b8f4a5..09cb9a131e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -381,16 +381,16 @@ public class VcnGatewayConnection extends StateMachine { /** The reason why the disconnect was requested. */ @NonNull public final String reason; - public final boolean shouldTeardown; + public final boolean shouldQuit; - EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldTeardown) { + EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) { this.reason = Objects.requireNonNull(reason); - this.shouldTeardown = shouldTeardown; + this.shouldQuit = shouldQuit; } @Override public int hashCode() { - return Objects.hash(reason, shouldTeardown); + return Objects.hash(reason, shouldQuit); } @Override @@ -400,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine { } final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; - return reason.equals(rhs.reason) && shouldTeardown == rhs.shouldTeardown; + return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit; } } @@ -493,8 +493,14 @@ public class VcnGatewayConnection extends StateMachine { */ @NonNull private final VcnWakeLock mWakeLock; - /** Running state of this VcnGatewayConnection. */ - private boolean mIsRunning = true; + /** + * Whether the VcnGatewayConnection is in the process of irreversibly quitting. + * + *

    This variable is false for the lifecycle of the VcnGatewayConnection, until a command to + * teardown has been received. This may be flipped due to events such as the Network becoming + * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure. + */ + private boolean mIsQuitting = false; /** * The token used by the primary/current/active session. @@ -628,7 +634,7 @@ public class VcnGatewayConnection extends StateMachine { */ public void teardownAsynchronously() { sendDisconnectRequestedAndAcquireWakelock( - DISCONNECT_REASON_TEARDOWN, true /* shouldTeardown */); + DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -698,7 +704,7 @@ public class VcnGatewayConnection extends StateMachine { private void acquireWakeLock() { mVcnContext.ensureRunningOnLooperThread(); - if (mIsRunning) { + if (!mIsQuitting) { mWakeLock.acquire(); } } @@ -897,8 +903,7 @@ public class VcnGatewayConnection extends StateMachine { TOKEN_ALL, 0 /* arg2 */, new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, - false /* shouldTeardown */)); + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */)); mDisconnectRequestAlarm = createScheduledAlarm( DISCONNECT_REQUEST_ALARM, @@ -916,7 +921,7 @@ public class VcnGatewayConnection extends StateMachine { removeEqualMessages( EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldTeardown */)); + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */)); } private void setRetryTimeoutAlarm(long delay) { @@ -1049,7 +1054,7 @@ public class VcnGatewayConnection extends StateMachine { } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } } @@ -1088,7 +1093,7 @@ public class VcnGatewayConnection extends StateMachine { } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } // Attempt to release the WakeLock - only possible if the Handler queue is empty @@ -1106,7 +1111,7 @@ public class VcnGatewayConnection extends StateMachine { } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } } @@ -1143,7 +1148,7 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180526152): notify VcnStatusCallback for Network loss Slog.v(TAG, "Tearing down. Cause: " + info.reason); - mIsRunning = !info.shouldTeardown; + mIsQuitting = info.shouldQuit; teardownNetwork(); @@ -1175,7 +1180,7 @@ public class VcnGatewayConnection extends StateMachine { private class DisconnectedState extends BaseState { @Override protected void enterState() { - if (!mIsRunning) { + if (mIsQuitting) { quitNow(); // Ignore all queued events; cleanup is complete. } @@ -1198,8 +1203,8 @@ public class VcnGatewayConnection extends StateMachine { } break; case EVENT_DISCONNECT_REQUESTED: - if (((EventDisconnectRequestedInfo) msg.obj).shouldTeardown) { - mIsRunning = false; + if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) { + mIsQuitting = true; quitNow(); } @@ -1285,7 +1290,7 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); - mIsRunning = !info.shouldTeardown; + mIsQuitting = info.shouldQuit; teardownNetwork(); if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { @@ -1301,7 +1306,7 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SESSION_CLOSED: mIkeSession = null; - if (mIsRunning && mUnderlying != null) { + if (!mIsQuitting && mUnderlying != null) { transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); } else { teardownNetwork(); @@ -1907,13 +1912,13 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - boolean isRunning() { - return mIsRunning; + boolean isQuitting() { + return mIsQuitting; } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setIsRunning(boolean isRunning) { - mIsRunning = isRunning; + void setIsQuitting(boolean isQuitting) { + mIsQuitting = isQuitting; } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -1927,11 +1932,11 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldTeardown) { + void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) { sendMessageAndAcquireWakeLock( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, - new EventDisconnectRequestedInfo(reason, shouldTeardown)); + new EventDisconnectRequestedInfo(reason, shouldQuit)); } private IkeSessionParams buildIkeParams() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 12c61cec87..035c385010 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -297,7 +297,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); - assertFalse(mGatewayConnection.isRunning()); + assertTrue(mGatewayConnection.isQuitting()); } @Test @@ -306,6 +306,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isRunning()); + assertFalse(mGatewayConnection.isQuitting()); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 0f94426e12..d07d2cf4f1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -120,7 +120,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); - assertFalse(mGatewayConnection.isRunning()); + assertTrue(mGatewayConnection.isQuitting()); } @Test @@ -129,6 +129,6 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isRunning()); + assertFalse(mGatewayConnection.isQuitting()); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index a978c335d5..5f27fabb62 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -57,7 +57,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect } @Test - public void testEnterWhileNotRunningTriggersQuit() throws Exception { + public void testEnterWhileQuittingTriggersQuit() throws Exception { final VcnGatewayConnection vgc = new VcnGatewayConnection( mVcnContext, @@ -67,7 +67,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mGatewayStatusCallback, mDeps); - vgc.setIsRunning(false); + vgc.setIsQuitting(true); vgc.transitionTo(vgc.mDisconnectedState); mTestLooper.dispatchAll(); @@ -104,7 +104,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); - assertFalse(mGatewayConnection.isRunning()); + assertTrue(mGatewayConnection.isQuitting()); verify(mGatewayStatusCallback).onQuit(); } @@ -114,7 +114,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isRunning()); + assertFalse(mGatewayConnection.isQuitting()); verify(mGatewayStatusCallback, never()).onQuit(); // No safe mode timer changes expected. } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index c57237c2f7..661e03af4f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -81,7 +81,7 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); - assertFalse(mGatewayConnection.isRunning()); + assertTrue(mGatewayConnection.isQuitting()); } @Test @@ -95,6 +95,6 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isRunning()); + assertFalse(mGatewayConnection.isQuitting()); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 1e8e7a0b77..85a0277f8b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -106,7 +106,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertNull(mGatewayConnection.getCurrentState()); - assertFalse(mGatewayConnection.isRunning()); + assertTrue(mGatewayConnection.isQuitting()); } @Test @@ -115,6 +115,6 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isRunning()); + assertFalse(mGatewayConnection.isQuitting()); } } From ad2a35a44962e1bf1b6c2624696387dc21683ea5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 1 Mar 2021 15:15:16 -0800 Subject: [PATCH 0104/1057] Call setUnderlyingNetwork to complete VCN MOBIKE This change updates the underlying network for the VCN in order to ensure full MOBIKE switches are handled. Bug: 169788130 Test: atest FrameworksVcnTests Change-Id: Ib439bde4217beeb28f425c08ed9f3376dfe0033c --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 09cb9a131e..6bc9978a07 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1478,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform transform, int direction) { try { - // TODO(b/180163196): Set underlying network of tunnel interface + tunnelIface.setUnderlyingNetwork(underlyingNetwork); // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 035c385010..69b2fb135a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -36,6 +36,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -143,11 +144,18 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); + verify(mIpSecSvc, times(2)) + .setNetworkForTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), + eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), + any()); + for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { verify(mIpSecSvc) .applyTunnelModeTransform( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } From 5bc055313f9e654648484c180850c7c9447c8304 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 16 Feb 2021 11:44:40 -0800 Subject: [PATCH 0105/1057] Expose APIs for VcnStatusCallback. This CL exposes the APIs needed to define VcnStatusCallback as well as register and unregister them. VcnStatusCallbacks should be registered by Carrier Apps to receive VCN-related status updates for their configured VCNs. Potential status updates include a VCN entering safe mode or an error with an underlying Network. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I1bf01139d4feea71f650acdbf98c6634c66acbbf --- .../src/android/net/vcn/VcnManager.java | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index eb8c251fec..c1d6edf898 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -359,8 +359,6 @@ public class VcnManager { /** * Value indicating that the VCN for the subscription group is not configured, or that the * callback is not privileged for the subscription group. - * - * @hide */ public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; @@ -369,8 +367,6 @@ public class VcnManager { * *

    A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the * provisioning package is not privileged. - * - * @hide */ public static final int VCN_STATUS_CODE_INACTIVE = 1; @@ -380,8 +376,6 @@ public class VcnManager { *

    A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered * active while it is connecting, fully connected, and disconnecting. - * - * @hide */ public static final int VCN_STATUS_CODE_ACTIVE = 2; @@ -391,8 +385,6 @@ public class VcnManager { *

    A VCN will be put into Safe Mode if any of the gateway connections were unable to * establish a connection within a system-determined timeout (while underlying networks were * available). - * - * @hide */ public static final int VCN_STATUS_CODE_SAFE_MODE = 3; @@ -407,8 +399,6 @@ public class VcnManager { /** * Value indicating that an internal failure occurred in this Gateway Connection. - * - * @hide */ public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; @@ -416,8 +406,6 @@ public class VcnManager { * Value indicating that an error with this Gateway Connection's configuration occurred. * *

    For example, this error code will be returned after authentication failures. - * - * @hide */ public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; @@ -427,19 +415,14 @@ public class VcnManager { *

    For example, this error code will be returned if an underlying {@link android.net.Network} * for this Gateway Connection is lost, or if an error occurs while resolving the connection * endpoint address. - * - * @hide */ public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; - // TODO: make VcnStatusCallback @SystemApi /** * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs. * *

    VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a * subscription group. - * - * @hide */ public abstract static class VcnStatusCallback { private VcnStatusCallbackBinder mCbBinder; @@ -451,11 +434,11 @@ public class VcnManager { * establish a connection within a system-determined timeout (while underlying networks were * available). * - *

    A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration - * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. - * + * @deprecated Removed in favor of {@link #onVcnStatusChanged(int)}. To be removed in a + * followup patch. * @hide */ + @Deprecated public void onEnteredSafeMode() {} /** @@ -467,15 +450,16 @@ public class VcnManager { public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** - * Invoked when a VCN Gateway Connection corresponding to this callback's subscription + * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group * encounters an error. * - * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway - * Connection that encountered the error for identification purposes. These will be a - * sorted list with no duplicates, matching one of the {@link + * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities + * for the Gateway Connection that encountered the error, for identification purposes. + * These will be a sorted list with no duplicates and will match {@link + * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription * group. - * @param errorCode {@link VcnErrorCode} to indicate the error that occurred + * @param errorCode the code to indicate the error that occurred * @param detail Throwable to provide additional information about the error, or {@code * null} if none */ @@ -496,6 +480,10 @@ public class VcnManager { *

    A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + *

    A {@link VcnStatusCallback} is eligible to begin receiving callbacks once it is registered + * and there is a VCN active for its specified subscription group (this may happen after the + * callback is registered). + * *

    {@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the * current status for the specified subscription group's VCN. If the registrant is not * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be @@ -505,7 +493,6 @@ public class VcnManager { * @param executor The {@link Executor} to be used for invoking callbacks * @param callback The VcnStatusCallback to be registered * @throws IllegalStateException if callback is currently registered with VcnManager - * @hide */ public void registerVcnStatusCallback( @NonNull ParcelUuid subscriptionGroup, @@ -538,7 +525,6 @@ public class VcnManager { * was registered with. * * @param callback The callback to be unregistered - * @hide */ public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) { requireNonNull(callback, "callback must not be null"); From 95d53da67de30b1faddaca900bb2771e35247435 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 19 Feb 2021 17:36:32 -0800 Subject: [PATCH 0106/1057] Remove VcnStatusCallback#onEnteredSafemode(). This CL removes VcnStatusCallback#onEnteredSafeMode(). This method was previously used to notify callbacks when their VCN entered Safe Mode. However, this is not needed now that VcnStatusCallback#onVcnStatusChanged(int) is defined. Bug: 1597023 Test: atest FrameworksVcnTests Change-Id: I8e47de9bf6763cd38025a552bee710673dddf843 --- .../android/net/vcn/IVcnStatusCallback.aidl | 1 - .../src/android/net/vcn/VcnManager.java | 20 ------------------- .../java/android/net/vcn/VcnManagerTest.java | 3 --- 3 files changed, 24 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl index d91cef592d..236ae8bb11 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl @@ -18,7 +18,6 @@ package android.net.vcn; /** @hide */ oneway interface IVcnStatusCallback { - void onEnteredSafeMode(); void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index c1d6edf898..8ebf757760 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -427,20 +427,6 @@ public class VcnManager { public abstract static class VcnStatusCallback { private VcnStatusCallbackBinder mCbBinder; - /** - * Invoked when the VCN for this Callback's subscription group enters safe mode. - * - *

    A VCN will be put into safe mode if any of the gateway connections were unable to - * establish a connection within a system-determined timeout (while underlying networks were - * available). - * - * @deprecated Removed in favor of {@link #onVcnStatusChanged(int)}. To be removed in a - * followup patch. - * @hide - */ - @Deprecated - public void onEnteredSafeMode() {} - /** * Invoked when status of the VCN for this callback's subscription group changes. * @@ -584,12 +570,6 @@ public class VcnManager { mCallback = callback; } - @Override - public void onEnteredSafeMode() { - Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); - } - @Override public void onVcnStatusChanged(@VcnStatusCode int statusCode) { Binder.withCleanCallingIdentity( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 66590c9257..7515971b83 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -203,9 +203,6 @@ public class VcnManagerTest { IVcnStatusCallback cbBinder = new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback); - cbBinder.onEnteredSafeMode(); - verify(mMockStatusCallback).onEnteredSafeMode(); - cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); From 56bb9a318dbd953767213b52a936d83996b76efd Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 19 Feb 2021 11:31:32 -0800 Subject: [PATCH 0107/1057] Call VcnStatusCallback#onVcnStatusChanged on register. This CL updates VcnMangementService to notify VcnStatusCallbacks on registration with the current status of the VCN for the specified subscription group. Bug: 180659281 Test: atest FrameworksVcnTests Change-Id: Id2c74e855fa12d21d292ee94a72ad047f2d56aca --- .../android/server/VcnManagementService.java | 66 ++++++--- .../server/VcnManagementServiceTest.java | 134 +++++++++++++++--- 2 files changed, 158 insertions(+), 42 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 8d5d3d939e..ad2f52401e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -35,6 +35,7 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnManager; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; @@ -724,6 +725,26 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private boolean isCallbackPermissioned( + @NonNull VcnStatusCallbackInfo cbInfo, @NonNull ParcelUuid subgroup) { + if (!subgroup.equals(cbInfo.mSubGroup)) { + return false; + } + + if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subgroup, cbInfo.mPkgName)) { + return false; + } + + if (!mLocationPermissionChecker.checkLocationPermission( + cbInfo.mPkgName, + "VcnStatusCallback" /* featureId */, + cbInfo.mUid, + null /* message */)) { + return false; + } + return true; + } + /** Registers the provided callback for receiving VCN status updates. */ @Override public void registerVcnStatusCallback( @@ -758,6 +779,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } mRegisteredStatusCallbacks.put(cbBinder, cbInfo); + + // now that callback is registered, send it the VCN's current status + final VcnConfig vcnConfig = mConfigs.get(subGroup); + final Vcn vcn = mVcns.get(subGroup); + final int vcnStatus; + if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) { + vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; + } else if (vcn == null) { + vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE; + } else if (vcn.isActive()) { + vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE; + } else { + // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status + vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE; + } + + try { + cbInfo.mCallback.onVcnStatusChanged(vcnStatus); + } catch (RemoteException e) { + Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); + } } } finally { Binder.restoreCallingIdentity(identity); @@ -806,26 +848,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup"); } - private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) { - if (!mSubGroup.equals(cbInfo.mSubGroup)) { - return false; - } - - if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup( - mSubGroup, cbInfo.mPkgName)) { - return false; - } - - if (!mLocationPermissionChecker.checkLocationPermission( - cbInfo.mPkgName, - "VcnStatusCallback" /* featureId */, - cbInfo.mUid, - null /* message */)) { - return false; - } - return true; - } - @Override public void onEnteredSafeMode() { synchronized (mLock) { @@ -838,7 +860,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo)) { + if (isCallbackPermissioned(cbInfo, mSubGroup)) { Binder.withCleanCallingIdentity( () -> cbInfo.mCallback.onVcnStatusChanged( @@ -862,7 +884,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo)) { + if (isCallbackPermissioned(cbInfo, mSubGroup)) { Binder.withCleanCallingIdentity( () -> cbInfo.mCallback.onGatewayConnectionError( diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 9b500a7271..73a6b88e29 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -100,6 +100,8 @@ import java.util.UUID; public class VcnManagementServiceTest { private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); + private static final String TEST_CB_PACKAGE_NAME = + VcnManagementServiceTest.class.getPackage().getName() + ".callback"; private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); private static final VcnConfig TEST_VCN_CONFIG; @@ -288,6 +290,14 @@ public class VcnManagementServiceTest { private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( Set activeSubscriptionGroups, Map subIdToGroupMap) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + Set activeSubscriptionGroups, + Map subIdToGroupMap, + boolean hasCarrierPrivileges) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); @@ -295,7 +305,7 @@ public class VcnManagementServiceTest { (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) ? Collections.emptySet() : Collections.singleton(TEST_PACKAGE_NAME); - doReturn(true) + doReturn(hasCarrierPrivileges) .when(snapshot) .packageHasPermissionsForSubscriptionGroup( argThat(val -> activeSubscriptionGroups.contains(val)), @@ -549,13 +559,6 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } - private void setUpVcnSubscription(int subId, ParcelUuid subGroup) { - mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); - - triggerSubscriptionTrackerCbAndGetSnapshot( - Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup)); - } - private void verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, @Transport int transportType, @@ -573,9 +576,23 @@ public class VcnManagementServiceTest { } private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) { - setUpVcnSubscription(subId, subGrp); + setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */); + } + + private void setupSubscriptionAndStartVcn( + int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { + mVcnMgmtSvc.systemReady(); + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(subGrp), + Collections.singletonMap(subId, subGrp), + hasCarrierPrivileges); + final Vcn vcn = startAndGetVcnInstance(subGrp); doReturn(isVcnActive).when(vcn).isActive(); + + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); } private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport( @@ -721,7 +738,7 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } - private void verifyVcnCallback( + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) throws Exception { verify(mMockDeps) @@ -732,20 +749,20 @@ public class VcnManagementServiceTest { eq(snapshot), mVcnCallbackCaptor.capture()); - mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - VcnCallback vcnCallback = mVcnCallbackCaptor.getValue(); vcnCallback.onEnteredSafeMode(); - - verify(mMockPolicyListener).onPolicyChanged(); } @Test - public void testVcnCallbackOnEnteredSafeMode() throws Exception { + public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); - verifyVcnCallback(TEST_UUID_1, snapshot); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + triggerVcnSafeMode(TEST_UUID_1, snapshot); + + verify(mMockPolicyListener).onPolicyChanged(); } private void triggerVcnStatusCallbackOnEnteredSafeMode( @@ -758,6 +775,9 @@ public class VcnManagementServiceTest { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup); + doReturn(hasPermissionsforSubGroup) .when(snapshot) .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName)); @@ -768,10 +788,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); - // Trigger systemReady() to set up LocationPermissionChecker - mVcnMgmtSvc.systemReady(); - - verifyVcnCallback(subGroup, snapshot); + triggerVcnSafeMode(subGroup, snapshot); } @Test @@ -825,6 +842,83 @@ public class VcnManagementServiceTest { assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName); assertEquals(TEST_UID, cbInfo.mUid); verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt()); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + + @Test + public void testRegisterVcnStatusCallback_MissingPermission() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + false /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + + @Test + public void testRegisterVcnStatusCallback_VcnInactive() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + true /* hasCarrierPrivileges */); + + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown + // timeout so the VCN goes inactive. + final TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(TEST_UUID_1), + Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), + false /* hasCarrierPrivileges */); + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + + // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE + // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE + // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without + // reactivating the VCN. + doReturn(true) + .when(snapshot) + .packageHasPermissionsForSubscriptionGroup( + eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME)); + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_CB_PACKAGE_NAME), any(), eq(TEST_UID), any()); + + mVcnMgmtSvc.registerVcnStatusCallback( + TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE); + } + + @Test + public void testRegisterVcnStatusCallback_VcnActive() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + true /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + + @Test + public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + false /* isActive */, + true /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test(expected = IllegalStateException.class) From 9284af7ee258df8871cfb55a3d68eab9b5effb14 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Feb 2021 18:19:17 -0800 Subject: [PATCH 0108/1057] Support converting IkeSessionParams to/from PersistableBundle Bug: 163604823 Test: Will be verified in the followup commit Change-Id: Ia8b97a4cd070a9144f955d48447e1ca2e604801b --- .../IkeSessionParamsUtils.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java new file mode 100644 index 0000000000..2d292c8308 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -0,0 +1,120 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Abstract utility class to convert IkeSessionParams to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeSessionParamsUtils { + private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY"; + private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; + private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; + private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; + private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; + private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; + private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; + private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY"; + private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; + + /** Serializes an IkeSessionParams to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) { + if (params.getConfiguredNetwork() != null || params.getIke3gppExtension() != null) { + throw new IllegalStateException( + "Cannot convert a IkeSessionParams with a caller configured network or with" + + " 3GPP extension enabled"); + } + + final PersistableBundle result = new PersistableBundle(); + + result.putString(SERVER_HOST_NAME_KEY, params.getServerHostname()); + + final PersistableBundle saProposalBundle = + PersistableBundleUtils.fromList( + params.getSaProposals(), IkeSaProposalUtils::toPersistableBundle); + result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle); + + result.putPersistableBundle( + LOCAL_ID_KEY, + IkeIdentificationUtils.toPersistableBundle(params.getLocalIdentification())); + result.putPersistableBundle( + REMOTE_ID_KEY, + IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification())); + + result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); + result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); + result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); + result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); + result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); + + // TODO: Handle authentication configuration, configuration requests and IKE options. + + return result; + } + + /** Constructs an IkeSessionParams by deserializing a PersistableBundle. */ + @NonNull + public static IkeSessionParams fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle is null"); + + final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(); + + builder.setServerHostname(in.getString(SERVER_HOST_NAME_KEY)); + + PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY); + Objects.requireNonNull(in, "SA Proposals was null"); + List saProposals = + PersistableBundleUtils.toList( + proposalBundle, IkeSaProposalUtils::fromPersistableBundle); + for (IkeSaProposal proposal : saProposals) { + builder.addSaProposal(proposal); + } + + builder.setLocalIdentification( + IkeIdentificationUtils.fromPersistableBundle( + in.getPersistableBundle(LOCAL_ID_KEY))); + builder.setRemoteIdentification( + IkeIdentificationUtils.fromPersistableBundle( + in.getPersistableBundle(REMOTE_ID_KEY))); + + builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY)); + builder.setLifetimeSeconds( + in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); + builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); + builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); + + // TODO: Handle authentication configuration, configuration requests and IKE options. + + return builder.build(); + } +} From d297a98cdceebda55edd90643bea1c995f91782e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 3 Mar 2021 20:37:26 -0800 Subject: [PATCH 0109/1057] Make VCN network policy listener oneway This change ensures that all VCN callbacks and interfaces are asynchronous, ensuring that the systemserver does not get deadlocked. Bug: 180968965 Test: atest FrameworksVcnTests Change-Id: I551137420bbd561ad53a6c06c8f91306901e51f4 --- .../android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl index f8ae492016..62de8216ce 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl @@ -17,6 +17,6 @@ package android.net.vcn; /** @hide */ -interface IVcnUnderlyingNetworkPolicyListener { +oneway interface IVcnUnderlyingNetworkPolicyListener { void onPolicyChanged(); } \ No newline at end of file From e4cb7b8c08a77a5d07bd5113c91ebf104dc1e3ce Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Feb 2021 10:31:18 -0800 Subject: [PATCH 0110/1057] Support converting IkeAuthConfig to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I97d9a7db423711dbccea412b96f069fe1dbd2779 --- .../IkeSessionParamsUtils.java | 105 +++++++++++++++++- .../IkeSessionParamsUtilsTest.java | 98 ++++++++++++++++ .../SaProposalUtilsTest.java | 30 ++--- 3 files changed, 218 insertions(+), 15 deletions(-) create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 2d292c8308..3527f3e252 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -21,11 +21,14 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -40,6 +43,8 @@ public final class IkeSessionParamsUtils { private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; + private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY"; + private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY"; private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; @@ -71,13 +76,18 @@ public final class IkeSessionParamsUtils { REMOTE_ID_KEY, IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification())); + result.putPersistableBundle( + LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig())); + result.putPersistableBundle( + REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig())); + result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); - // TODO: Handle authentication configuration, configuration requests and IKE options. + // TODO: Handle configuration requests and IKE options. return result; } @@ -107,14 +117,105 @@ public final class IkeSessionParamsUtils { IkeIdentificationUtils.fromPersistableBundle( in.getPersistableBundle(REMOTE_ID_KEY))); + AuthConfigUtils.setBuilderByReadingPersistableBundle( + in.getPersistableBundle(LOCAL_AUTH_KEY), + in.getPersistableBundle(REMOTE_AUTH_KEY), + builder); + builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY)); builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); - // TODO: Handle authentication configuration, configuration requests and IKE options. + // TODO: Handle configuration requests and IKE options. return builder.build(); } + + private static final class AuthConfigUtils { + private static final int IKE_AUTH_METHOD_PSK = 1; + private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2; + private static final int IKE_AUTH_METHOD_EAP = 3; + + private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) { + if (authConfig instanceof IkeAuthPskConfig) { + IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig; + return IkeAuthPskConfigUtils.toPersistableBundle( + config, createPersistableBundle(IKE_AUTH_METHOD_PSK)); + } else { + throw new IllegalStateException("Invalid IkeAuthConfig subclass"); + } + + // TODO: Handle EAP auth and digital signature based auth. + } + + private static PersistableBundle createPersistableBundle(int type) { + final PersistableBundle result = new PersistableBundle(); + result.putInt(AUTH_METHOD_KEY, type); + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle localAuthBundle, + @NonNull PersistableBundle remoteAuthBundle, + @NonNull IkeSessionParams.Builder builder) { + Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); + Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); + + final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY); + final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY); + switch (localMethodType) { + case IKE_AUTH_METHOD_PSK: + if (remoteMethodType != IKE_AUTH_METHOD_PSK) { + throw new IllegalArgumentException( + "Expect remote auth method to be PSK based, but was " + + remoteMethodType); + } + IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( + localAuthBundle, remoteAuthBundle, builder); + break; + default: + throw new IllegalArgumentException( + "Invalid EAP method type " + localMethodType); + } + // TODO: Handle EAP auth and digital signature based auth. + } + } + + private static final class IkeAuthPskConfigUtils { + private static final String PSK_KEY = "PSK_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle( + @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) { + result.putPersistableBundle( + PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk())); + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle localAuthBundle, + @NonNull PersistableBundle remoteAuthBundle, + @NonNull IkeSessionParams.Builder builder) { + Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); + Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); + + final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY); + final PersistableBundle remotePskBundle = + remoteAuthBundle.getPersistableBundle(PSK_KEY); + Objects.requireNonNull(localAuthBundle, "Local PSK was null"); + Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null"); + + final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle); + final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle); + if (!Arrays.equals(localPsk, remotePsk)) { + throw new IllegalArgumentException("Local PSK and remote PSK are different"); + } + builder.setAuthPsk(localPsk); + } + } } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java new file mode 100644 index 0000000000..be93d4e753 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -0,0 +1,98 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSessionParams; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IkeSessionParamsUtilsTest { + private static IkeSessionParams.Builder createBuilderMinimum() { + final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); + + return new IkeSessionParams.Builder() + .setServerHostname(serverAddress.getHostAddress()) + .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal()) + .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) + .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) + .setAuthPsk("psk".getBytes()); + } + + private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) { + final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params); + final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle); + + assertEquals(result, params); + } + + @Test + public void testEncodeRecodeParamsWithLifetimes() throws Exception { + final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L); + final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L); + final IkeSessionParams params = + createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + + @Test + public void testEncodeRecodeParamsWithDpdDelay() throws Exception { + final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L); + final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + + @Test + public void testEncodeRecodeParamsWithNattKeepalive() throws Exception { + final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L); + final IkeSessionParams params = + createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + + @Test + public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception { + final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500}; + final IkeSessionParams params = + createBuilderMinimum() + .setRetransmissionTimeoutsMillis(retransmissionTimeout) + .build(); + + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + + @Test + public void testEncodeRecodeParamsWithAuthPsk() throws Exception { + final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java index 8ae8692b4f..664044a9e7 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -32,21 +32,25 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class SaProposalUtilsTest { + /** Package private so that IkeSessionParamsUtilsTest can use it */ + static IkeSaProposal buildTestIkeSaProposal() { + return new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) + .build(); + } + @Test public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { - final IkeSaProposal proposal = - new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) - .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) - .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) - .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) - .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256) - .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) - .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) - .build(); + final IkeSaProposal proposal = buildTestIkeSaProposal(); final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal); final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle); From a54d5dee2b651944c468ac282ea2500758a9c254 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Feb 2021 15:41:16 -0800 Subject: [PATCH 0111/1057] Support converting IkeAuthDigitalSignConfig to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I62cdf4cb0297a394e0c97973e621b5c051ab0192 --- .../vcn/persistablebundleutils/CertUtils.java | 22 +++- .../IkeSessionParamsUtils.java | 121 ++++++++++++++++++ Vcn/tests/unit/assets/client-end-cert.pem | 21 +++ Vcn/tests/unit/assets/client-private-key.key | 28 ++++ .../IkeSessionParamsUtilsTest.java | 38 ++++++ 5 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 Vcn/tests/unit/assets/client-end-cert.pem create mode 100644 Vcn/tests/unit/assets/client-private-key.key diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java index b6036b4a6f..35b3186877 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/CertUtils.java @@ -18,18 +18,24 @@ package android.net.vcn.persistablebundleutils; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.Objects; /** - * CertUtils provides utility methods for constructing Certificate. + * CertUtils provides utility methods for constructing Certificate and PrivateKey. * * @hide */ public class CertUtils { private static final String CERT_TYPE_X509 = "X.509"; + private static final String PRIVATE_KEY_TYPE_RSA = "RSA"; /** Decodes an ASN.1 DER encoded Certificate */ public static X509Certificate certificateFromByteArray(byte[] derEncoded) { @@ -43,4 +49,18 @@ public class CertUtils { throw new IllegalArgumentException("Fail to decode certificate", e); } } + + /** Decodes a PKCS#8 encoded RSA private key */ + public static RSAPrivateKey privateKeyFromByteArray(byte[] pkcs8Encoded) { + Objects.requireNonNull(pkcs8Encoded, "pkcs8Encoded was null"); + PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8Encoded); + + try { + KeyFactory keyFactory = KeyFactory.getInstance(PRIVATE_KEY_TYPE_RSA); + + return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalArgumentException("Fail to decode PrivateKey", e); + } + } } diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 3527f3e252..6f957c55b5 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -22,12 +22,18 @@ import android.annotation.NonNull; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; +import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; +import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -146,6 +152,14 @@ public final class IkeSessionParamsUtils { IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig; return IkeAuthPskConfigUtils.toPersistableBundle( config, createPersistableBundle(IKE_AUTH_METHOD_PSK)); + } else if (authConfig instanceof IkeAuthDigitalSignLocalConfig) { + IkeAuthDigitalSignLocalConfig config = (IkeAuthDigitalSignLocalConfig) authConfig; + return IkeAuthDigitalSignConfigUtils.toPersistableBundle( + config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE)); + } else if (authConfig instanceof IkeAuthDigitalSignRemoteConfig) { + IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig; + return IkeAuthDigitalSignConfigUtils.toPersistableBundle( + config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE)); } else { throw new IllegalStateException("Invalid IkeAuthConfig subclass"); } @@ -178,6 +192,15 @@ public final class IkeSessionParamsUtils { IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( localAuthBundle, remoteAuthBundle, builder); break; + case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE: + if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) { + throw new IllegalArgumentException( + "Expect remote auth method to be digital signature based, but was " + + remoteMethodType); + } + IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle( + localAuthBundle, remoteAuthBundle, builder); + break; default: throw new IllegalArgumentException( "Invalid EAP method type " + localMethodType); @@ -218,4 +241,102 @@ public final class IkeSessionParamsUtils { builder.setAuthPsk(localPsk); } } + + private static class IkeAuthDigitalSignConfigUtils { + private static final String END_CERT_KEY = "END_CERT_KEY"; + private static final String INTERMEDIATE_CERTS_KEY = "INTERMEDIATE_CERTS_KEY"; + private static final String PRIVATE_KEY_KEY = "PRIVATE_KEY_KEY"; + private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle( + @NonNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result) { + try { + result.putPersistableBundle( + END_CERT_KEY, + PersistableBundleUtils.fromByteArray( + config.getClientEndCertificate().getEncoded())); + + final List certList = config.getIntermediateCertificates(); + final List encodedCertList = new ArrayList<>(certList.size()); + for (X509Certificate cert : certList) { + encodedCertList.add(cert.getEncoded()); + } + + final PersistableBundle certsBundle = + PersistableBundleUtils.fromList( + encodedCertList, PersistableBundleUtils::fromByteArray); + result.putPersistableBundle(INTERMEDIATE_CERTS_KEY, certsBundle); + } catch (CertificateEncodingException e) { + throw new IllegalArgumentException("Fail to encode certificate"); + } + + // TODO: b/170670506 Consider putting PrivateKey in Android KeyStore + result.putPersistableBundle( + PRIVATE_KEY_KEY, + PersistableBundleUtils.fromByteArray(config.getPrivateKey().getEncoded())); + return result; + } + + @NonNull + public static PersistableBundle toPersistableBundle( + @NonNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result) { + try { + X509Certificate caCert = config.getRemoteCaCert(); + if (caCert != null) { + result.putPersistableBundle( + TRUST_CERT_KEY, + PersistableBundleUtils.fromByteArray(caCert.getEncoded())); + } + } catch (CertificateEncodingException e) { + throw new IllegalArgumentException("Fail to encode the certificate"); + } + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle localAuthBundle, + @NonNull PersistableBundle remoteAuthBundle, + @NonNull IkeSessionParams.Builder builder) { + Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); + Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); + + // Deserialize localAuth + final PersistableBundle endCertBundle = + localAuthBundle.getPersistableBundle(END_CERT_KEY); + Objects.requireNonNull(endCertBundle, "End cert was null"); + final byte[] encodedCert = PersistableBundleUtils.toByteArray(endCertBundle); + final X509Certificate endCert = CertUtils.certificateFromByteArray(encodedCert); + + final PersistableBundle certsBundle = + localAuthBundle.getPersistableBundle(INTERMEDIATE_CERTS_KEY); + Objects.requireNonNull(certsBundle, "Intermediate certs was null"); + final List encodedCertList = + PersistableBundleUtils.toList(certsBundle, PersistableBundleUtils::toByteArray); + final List certList = new ArrayList<>(encodedCertList.size()); + for (byte[] encoded : encodedCertList) { + certList.add(CertUtils.certificateFromByteArray(encoded)); + } + + final PersistableBundle privateKeyBundle = + localAuthBundle.getPersistableBundle(PRIVATE_KEY_KEY); + Objects.requireNonNull(privateKeyBundle, "PrivateKey bundle was null"); + final PrivateKey privateKey = + CertUtils.privateKeyFromByteArray( + PersistableBundleUtils.toByteArray(privateKeyBundle)); + + // Deserialize remoteAuth + final PersistableBundle trustCertBundle = + remoteAuthBundle.getPersistableBundle(TRUST_CERT_KEY); + + X509Certificate caCert = null; + if (trustCertBundle != null) { + final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle); + caCert = CertUtils.certificateFromByteArray(encodedCaCert); + } + + builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey); + } + } } diff --git a/Vcn/tests/unit/assets/client-end-cert.pem b/Vcn/tests/unit/assets/client-end-cert.pem new file mode 100644 index 0000000000..e82da85c50 --- /dev/null +++ b/Vcn/tests/unit/assets/client-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/Vcn/tests/unit/assets/client-private-key.key b/Vcn/tests/unit/assets/client-private-key.key new file mode 100644 index 0000000000..22736e98e0 --- /dev/null +++ b/Vcn/tests/unit/assets/client-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/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index be93d4e753..d857aaedf6 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -23,13 +23,22 @@ import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionParams; import android.os.PersistableBundle; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.org.bouncycastle.util.io.pem.PemObject; +import com.android.internal.org.bouncycastle.util.io.pem.PemReader; + import org.junit.Test; import org.junit.runner.RunWith; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.InetAddress; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -95,4 +104,33 @@ public class IkeSessionParamsUtilsTest { final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } + + private static InputStream openAssetsFile(String fileName) throws Exception { + return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName); + } + + private static X509Certificate createCertFromPemFile(String fileName) throws Exception { + final CertificateFactory factory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) factory.generateCertificate(openAssetsFile(fileName)); + } + + private static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception { + final PemObject pemObject = + new PemReader(new InputStreamReader(openAssetsFile(fileName))).readPemObject(); + return (RSAPrivateKey) CertUtils.privateKeyFromByteArray(pemObject.getContent()); + } + + @Test + public void testEncodeRecodeParamsWithDigitalSignAuth() throws Exception { + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + final X509Certificate clientEndCert = createCertFromPemFile("client-end-cert.pem"); + final RSAPrivateKey clientPrivateKey = + createRsaPrivateKeyFromKeyFile("client-private-key.key"); + + final IkeSessionParams params = + createBuilderMinimum() + .setAuthDigitalSignature(serverCaCert, clientEndCert, clientPrivateKey) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } } From 6552a0b124249d35e1cbecbbb094e5534052368c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Feb 2021 16:35:35 -0800 Subject: [PATCH 0112/1057] Support converting IkeAuthEapConfig to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: Ifaddd113d9267664404d75b7e4e5410622bf5d7b --- .../IkeSessionParamsUtils.java | 60 +++++++++++++++++-- .../IkeSessionParamsUtilsTest.java | 22 +++++++ 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 6f957c55b5..7f0c3280ea 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -19,11 +19,13 @@ package android.net.vcn.persistablebundleutils; import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; +import android.net.eap.EapSessionConfig; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; +import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.os.PersistableBundle; @@ -160,11 +162,13 @@ public final class IkeSessionParamsUtils { IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig; return IkeAuthDigitalSignConfigUtils.toPersistableBundle( config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE)); + } else if (authConfig instanceof IkeAuthEapConfig) { + IkeAuthEapConfig config = (IkeAuthEapConfig) authConfig; + return IkeAuthEapConfigUtils.toPersistableBundle( + config, createPersistableBundle(IKE_AUTH_METHOD_EAP)); } else { throw new IllegalStateException("Invalid IkeAuthConfig subclass"); } - - // TODO: Handle EAP auth and digital signature based auth. } private static PersistableBundle createPersistableBundle(int type) { @@ -191,7 +195,7 @@ public final class IkeSessionParamsUtils { } IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( localAuthBundle, remoteAuthBundle, builder); - break; + return; case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE: if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) { throw new IllegalArgumentException( @@ -200,12 +204,21 @@ public final class IkeSessionParamsUtils { } IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle( localAuthBundle, remoteAuthBundle, builder); - break; + return; + case IKE_AUTH_METHOD_EAP: + if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) { + throw new IllegalArgumentException( + "When using EAP for local authentication, expect remote auth" + + " method to be digital signature based, but was " + + remoteMethodType); + } + IkeAuthEapConfigUtils.setBuilderByReadingPersistableBundle( + localAuthBundle, remoteAuthBundle, builder); + return; default: throw new IllegalArgumentException( "Invalid EAP method type " + localMethodType); } - // TODO: Handle EAP auth and digital signature based auth. } } @@ -339,4 +352,41 @@ public final class IkeSessionParamsUtils { builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey); } } + + private static final class IkeAuthEapConfigUtils { + private static final String EAP_CONFIG_KEY = "EAP_CONFIG_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle( + @NonNull IkeAuthEapConfig config, @NonNull PersistableBundle result) { + result.putPersistableBundle( + EAP_CONFIG_KEY, + EapSessionConfigUtils.toPersistableBundle(config.getEapConfig())); + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle localAuthBundle, + @NonNull PersistableBundle remoteAuthBundle, + @NonNull IkeSessionParams.Builder builder) { + // Deserialize localAuth + final PersistableBundle eapBundle = + localAuthBundle.getPersistableBundle(EAP_CONFIG_KEY); + Objects.requireNonNull(eapBundle, "EAP Config was null"); + final EapSessionConfig eapConfig = + EapSessionConfigUtils.fromPersistableBundle(eapBundle); + + // Deserialize remoteAuth + final PersistableBundle trustCertBundle = + remoteAuthBundle.getPersistableBundle( + IkeAuthDigitalSignConfigUtils.TRUST_CERT_KEY); + + X509Certificate serverCaCert = null; + if (trustCertBundle != null) { + final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle); + serverCaCert = CertUtils.certificateFromByteArray(encodedCaCert); + } + builder.setAuthEap(serverCaCert, eapConfig); + } + } } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index d857aaedf6..720d44a5b6 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -16,9 +16,12 @@ package android.net.vcn.persistablebundleutils; +import static android.telephony.TelephonyManager.APPTYPE_USIM; + import static org.junit.Assert.assertEquals; import android.net.InetAddresses; +import android.net.eap.EapSessionConfig; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionParams; import android.os.PersistableBundle; @@ -36,6 +39,7 @@ import org.junit.runner.RunWith; import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetAddress; +import java.nio.charset.StandardCharsets; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; @@ -133,4 +137,22 @@ public class IkeSessionParamsUtilsTest { .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } + + @Test + public void testEncodeRecodeParamsWithEapAuth() throws Exception { + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + + final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); + final int subId = 1; + final EapSessionConfig eapConfig = + new EapSessionConfig.Builder() + .setEapIdentity(eapId) + .setEapSimConfig(subId, APPTYPE_USIM) + .setEapAkaConfig(subId, APPTYPE_USIM) + .build(); + + final IkeSessionParams params = + createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } } From 5659aaced66ffa827fe7b3fd81ebc5de716dcd63 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Feb 2021 18:07:29 -0800 Subject: [PATCH 0113/1057] Support converting IkeConfigRequest to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I9a0f7ad91de41749fdf05629bf86bdb010ba13fb --- .../IkeSessionParamsUtils.java | 98 ++++++++++++++++++- .../IkeSessionParamsUtilsTest.java | 21 ++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 7f0c3280ea..f54cc03bd6 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -16,22 +16,31 @@ package android.net.vcn.persistablebundleutils; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; import android.net.eap.EapSessionConfig; 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.IkeAuthConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; +import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; +import java.net.InetAddress; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; @@ -53,6 +62,7 @@ public final class IkeSessionParamsUtils { private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY"; private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY"; + private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; @@ -89,13 +99,21 @@ public final class IkeSessionParamsUtils { result.putPersistableBundle( REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig())); + final List reqList = new ArrayList<>(); + for (IkeConfigRequest req : params.getConfigurationRequests()) { + reqList.add(new ConfigRequest(req)); + } + final PersistableBundle configReqListBundle = + PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); + result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); + result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); - // TODO: Handle configuration requests and IKE options. + // TODO: Handle IKE options. return result; } @@ -136,7 +154,33 @@ public final class IkeSessionParamsUtils { builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); - // TODO: Handle configuration requests and IKE options. + final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); + Objects.requireNonNull(configReqListBundle, "Config request list was null"); + final List reqList = + PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); + for (ConfigRequest req : reqList) { + switch (req.type) { + case ConfigRequest.IPV4_P_CSCF_ADDRESS: + if (req.address == null) { + builder.addPcscfServerRequest(AF_INET); + } else { + builder.addPcscfServerRequest(req.address); + } + break; + case ConfigRequest.IPV6_P_CSCF_ADDRESS: + if (req.address == null) { + builder.addPcscfServerRequest(AF_INET6); + } else { + builder.addPcscfServerRequest(req.address); + } + break; + default: + throw new IllegalArgumentException( + "Unrecognized config request type: " + req.type); + } + } + + // TODO: Handle IKE options. return builder.build(); } @@ -389,4 +433,54 @@ public final class IkeSessionParamsUtils { builder.setAuthEap(serverCaCert, eapConfig); } } + + private static final class ConfigRequest { + private static final int IPV4_P_CSCF_ADDRESS = 1; + private static final int IPV6_P_CSCF_ADDRESS = 2; + + private static final String TYPE_KEY = "type"; + private static final String ADDRESS_KEY = "address"; + + public final int type; + + // Null when it is an empty request + @Nullable public final InetAddress address; + + ConfigRequest(IkeConfigRequest config) { + if (config instanceof ConfigRequestIpv4PcscfServer) { + type = IPV4_P_CSCF_ADDRESS; + address = ((ConfigRequestIpv4PcscfServer) config).getAddress(); + } else if (config instanceof ConfigRequestIpv6PcscfServer) { + type = IPV6_P_CSCF_ADDRESS; + address = ((ConfigRequestIpv6PcscfServer) config).getAddress(); + } else { + throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); + } + } + + ConfigRequest(PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + type = in.getInt(TYPE_KEY); + + String addressStr = in.getString(ADDRESS_KEY); + if (addressStr == null) { + address = null; + } else { + address = InetAddresses.parseNumericAddress(addressStr); + } + } + + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(TYPE_KEY, type); + if (address != null) { + result.putString(ADDRESS_KEY, address.getHostAddress()); + } + + return result; + } + } } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 720d44a5b6..625f52c7b0 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -16,6 +16,8 @@ package android.net.vcn.persistablebundleutils; +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.assertEquals; @@ -38,6 +40,8 @@ import org.junit.runner.RunWith; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.nio.charset.StandardCharsets; import java.security.cert.CertificateFactory; @@ -103,6 +107,23 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } + @Test + public void testEncodeRecodeParamsWithConfigRequests() throws Exception { + final Inet4Address ipv4Address = + (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); + final Inet6Address ipv6Address = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); + + final IkeSessionParams params = + createBuilderMinimum() + .addPcscfServerRequest(AF_INET) + .addPcscfServerRequest(AF_INET6) + .addPcscfServerRequest(ipv4Address) + .addPcscfServerRequest(ipv6Address) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + @Test public void testEncodeRecodeParamsWithAuthPsk() throws Exception { final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); From 2efd8e51284de87a7b804635c01692cc478eca4e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Feb 2021 21:03:05 -0800 Subject: [PATCH 0114/1057] Support converting IKE Options to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I28cad3cf4d8ccccb8233f76c631db3a302eb320b --- .../IkeSessionParamsUtils.java | 31 +++++++++++++++++-- .../IkeSessionParamsUtilsTest.java | 10 ++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index f54cc03bd6..9d3462cb0b 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -36,6 +36,7 @@ import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import android.os.PersistableBundle; +import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; @@ -48,6 +49,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Abstract utility class to convert IkeSessionParams to/from PersistableBundle. @@ -68,6 +70,15 @@ public final class IkeSessionParamsUtils { private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY"; private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; + private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; + + private static final Set IKE_OPTIONS = new ArraySet<>(); + + static { + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); + } /** Serializes an IkeSessionParams to a PersistableBundle. */ @NonNull @@ -113,7 +124,15 @@ public final class IkeSessionParamsUtils { result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); - // TODO: Handle IKE options. + final List enabledIkeOptions = new ArrayList<>(); + for (int option : IKE_OPTIONS) { + if (params.hasIkeOption(option)) { + enabledIkeOptions.add(option); + } + } + + final int[] optionArray = enabledIkeOptions.stream().mapToInt(i -> i).toArray(); + result.putIntArray(IKE_OPTIONS_KEY, optionArray); return result; } @@ -180,7 +199,15 @@ public final class IkeSessionParamsUtils { } } - // TODO: Handle IKE options. + // Clear IKE Options that are by default enabled + for (int option : IKE_OPTIONS) { + builder.removeIkeOption(option); + } + + final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY); + for (int option : optionArray) { + builder.addIkeOption(option); + } return builder.build(); } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 625f52c7b0..546d957d41 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -130,6 +130,16 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } + @Test + public void testEncodeRecodeParamsWithIkeOptions() throws Exception { + final IkeSessionParams params = + createBuilderMinimum() + .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(params); + } + private static InputStream openAssetsFile(String fileName) throws Exception { return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName); } From 6c5246ac3229c8472093e9bc6dbfbda7699c4b22 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 25 Feb 2021 14:48:39 -0800 Subject: [PATCH 0115/1057] Support converting VcnControlPlaneIkeConfig to/from PersistableBundle Bug: 163604823 Test: FrameworksVcnTests(new tests added) Change-Id: I38d066949d1543dc6b53a9e00ab6c1d1bd820c5f --- .../net/vcn/VcnControlPlaneIkeConfig.java | 42 +++++++++++-------- .../net/vcn/VcnControlPlaneIkeConfigTest.java | 7 ++++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java index de086f63b1..22d7faf2fe 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java @@ -19,11 +19,13 @@ package android.net.vcn; import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE; import android.annotation.NonNull; -import android.annotation.Nullable; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.vcn.persistablebundleutils.IkeSessionParamsUtils; +import android.net.vcn.persistablebundleutils.TunnelModeChildSessionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; +import android.util.Log; import java.util.Objects; @@ -38,14 +40,11 @@ import java.util.Objects; public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName(); - // STOPSHIP: b/163604823 Make mIkeParams and mChildParams @NonNull when it is supported to - // construct mIkeParams and mChildParams from PersistableBundles. - private static final String IKE_PARAMS_KEY = "mIkeParams"; - @Nullable private final IkeSessionParams mIkeParams; + @NonNull private final IkeSessionParams mIkeParams; private static final String CHILD_PARAMS_KEY = "mChildParams"; - @Nullable private final TunnelModeChildSessionParams mChildParams; + @NonNull private final TunnelModeChildSessionParams mChildParams; private static final ArraySet BUNDLE_KEY_SET = new ArraySet<>(); @@ -80,11 +79,19 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY); final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY); - // STOPSHIP: b/163604823 Support constructing mIkeParams and mChildParams from - // PersistableBundles. + Objects.requireNonNull(ikeParamsBundle, "IKE Session Params was null"); + Objects.requireNonNull(childParamsBundle, "Child Session Params was null"); - mIkeParams = null; - mChildParams = null; + mIkeParams = IkeSessionParamsUtils.fromPersistableBundle(ikeParamsBundle); + mChildParams = TunnelModeChildSessionParamsUtils.fromPersistableBundle(childParamsBundle); + + for (String key : in.keySet()) { + if (!BUNDLE_KEY_SET.contains(key)) { + Log.w(TAG, "Found an unexpected key in the PersistableBundle: " + key); + } + } + + validate(); } private void validate() { @@ -101,9 +108,11 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { @NonNull public PersistableBundle toPersistableBundle() { final PersistableBundle result = super.toPersistableBundle(); - - // STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to - // PersistableBundles. + result.putPersistableBundle( + IKE_PARAMS_KEY, IkeSessionParamsUtils.toPersistableBundle(mIkeParams)); + result.putPersistableBundle( + CHILD_PARAMS_KEY, + TunnelModeChildSessionParamsUtils.toPersistableBundle(mChildParams)); return result; } @@ -134,10 +143,9 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o; - // STOPSHIP: b/163604823 Also check mIkeParams and mChildParams when it is supported to - // construct mIkeParams and mChildParams from PersistableBundles. They are not checked - // now so that VcnGatewayConnectionConfigTest and VcnConfigTest can pass. - return super.equals(o); + return super.equals(o) + && Objects.equals(mIkeParams, other.mIkeParams) + && Objects.equals(mChildParams, other.mChildParams); } /** @hide */ diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java index 36f5e41462..2333718d0c 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java @@ -98,6 +98,13 @@ public class VcnControlPlaneIkeConfigTest { assertEquals(CHILD_PARAMS, config.getChildSessionParams()); } + @Test + public void testPersistableBundle() { + final VcnControlPlaneIkeConfig config = buildTestConfig(); + + assertEquals(config, new VcnControlPlaneIkeConfig(config.toPersistableBundle())); + } + @Test public void testConstructConfigWithoutIkeParams() { try { From 3eb20ab733e70afb676c6049b5570bd9f5858013 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 4 Mar 2021 10:50:02 -0800 Subject: [PATCH 0116/1057] Use actual Wifi subId when applying Network policies. This CL updates Network policy application to check against a Wifi Network's actual subscription id (previously, all Wifi Networks appeared to have subId INVALID_SUBSCRIPTION). Bug: 178501049 Test: atest FrameworksVcnTests Change-Id: I83f51e3351940bbb791bcc40bc75fe04baf68171 --- Vcn/service-b/src/com/android/server/VcnManagementService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index ad2f52401e..f73c9a2620 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -314,8 +314,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Gets the subId indicated by the given {@link WifiInfo}. */ public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) { - // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + return wifiInfo.getSubscriptionId(); } /** Creates a new LocationPermissionChecker for the provided Context. */ From effb03cef274f17475d09ef9f38c5a00abef5b6f Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 1 Mar 2021 11:39:18 -0800 Subject: [PATCH 0117/1057] Notify VcnStatusCallbacks for VCN start/stop. This CL updates VcnManagementService to notify VcnStatusCallbacks when a VCN is started or stopped. VcnStatusCallbacks will also be notified for config changes that cause a VCN to exit Safe Mode. Bug: 180659281 Test: atest FrameworksVcnTests Change-Id: I4168c868185880621333855dfcb51e46cb662741 --- .../android/server/VcnManagementService.java | 53 +++++++++++++++---- .../server/VcnManagementServiceTest.java | 39 ++++++++++++++ 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index ad2f52401e..0eca09e8d8 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -16,6 +16,9 @@ package com.android.server; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -37,6 +40,7 @@ import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnManager.VcnErrorCode; +import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.Binder; @@ -421,6 +425,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Carrier App manually removing/adding a VcnConfig. if (mVcns.get(uuidToTeardown) == instanceToTeardown) { stopVcnLocked(uuidToTeardown); + + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } } }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -454,6 +463,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + @GuardedBy("mLock") + private void notifyAllPermissionedStatusCallbacksLocked( + @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { + for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { + if (isCallbackPermissioned(cbInfo, subGroup)) { + Binder.withCleanCallingIdentity( + () -> cbInfo.mCallback.onVcnStatusChanged(statusCode)); + } + } + } + @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); @@ -470,6 +490,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Now that a new VCN has started, notify all registered listeners to refresh their // UnderlyingNetworkPolicy. notifyAllPolicyListenersLocked(); + + // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback + notifyAllPermissionedStatusCallbacksLocked(subscriptionGroup, VCN_STATUS_CODE_ACTIVE); } @GuardedBy("mLock") @@ -478,7 +501,16 @@ public class VcnManagementService extends IVcnManagementService.Stub { Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { - mVcns.get(subscriptionGroup).updateConfig(config); + final Vcn vcn = mVcns.get(subscriptionGroup); + final boolean isActive = vcn.isActive(); + vcn.updateConfig(config); + + // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode + if (!isActive) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_ACTIVE); + } } else { startVcnLocked(subscriptionGroup, config); } @@ -531,9 +563,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { mConfigs.remove(subscriptionGroup); + final boolean vcnExists = mVcns.containsKey(subscriptionGroup); stopVcnLocked(subscriptionGroup); + if (vcnExists) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through + // VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); + } + writeConfigsToDiskLocked(); } }); @@ -857,16 +897,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { } notifyAllPolicyListenersLocked(); - - // Notify all registered StatusCallbacks for this subGroup - for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo, mSubGroup)) { - Binder.withCleanCallingIdentity( - () -> - cbInfo.mCallback.onVcnStatusChanged( - VCN_STATUS_CODE_SAFE_MODE)); - } - } + notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE); } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 73a6b88e29..11498dec81 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -460,6 +460,34 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testSetVcnConfigNotifiesStatusCallback() throws Exception { + mVcnMgmtSvc.systemReady(); + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + + @Test + public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception { + setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */); + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); + + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + @Test public void testClearVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -502,6 +530,17 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testClearVcnConfigNotifiesStatusCallback() throws Exception { + setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */); + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + @Test public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { // Use a different UUID to simulate a new VCN config. From 5ed27fd0e90f280290cfbd98285f4e45eed2061e Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 1 Mar 2021 17:19:24 -0800 Subject: [PATCH 0118/1057] Exit Safe Mode when a VCN gets new configs. This CL updates VCN instances to exit Safe Mode when they receive a new VcnConfig. When a VCN exits Safe Mode, they will re-register a request listener to receive all cached requests and start the needed VcnGatewayConnections. Bug: 179429339 Test: atest FrameworksVcnTests Change-Id: Id1c2dc287e1ec56f37821cf0ae77f066f22d22bb --- .../src/com/android/server/vcn/Vcn.java | 14 +++- .../java/com/android/server/vcn/VcnTest.java | 69 ++++++++++++++----- 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 9d39c67d27..c55913e2e5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -128,7 +128,6 @@ public class Vcn extends Handler { * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN * Looper. */ - // TODO(b/179429339): update when exiting safemode (when a new VcnConfig is provided) private final AtomicBoolean mIsActive = new AtomicBoolean(true); public Vcn( @@ -203,7 +202,8 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { - if (!isActive()) { + // Ignore if this Vcn is not active and we're not receiving new configs + if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) { return; } @@ -237,7 +237,13 @@ public class Vcn extends Handler { mConfig = config; - // TODO: Reevaluate active VcnGatewayConnection(s) + // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s) + + if (!mIsActive.getAndSet(true)) { + // If this VCN was not previously active, it is exiting Safe Mode. Re-register the + // request listener to get NetworkRequests again (and all cached requests). + mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); + } } private void handleTeardown() { @@ -253,6 +259,8 @@ public class Vcn extends Handler { private void handleEnterSafeMode() { handleTeardown(); + mVcnGatewayConnections.clear(); + mVcnCallback.onEnteredSafeMode(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 3dd710afed..4fa63d4ff6 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -22,7 +22,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -48,6 +50,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.util.Arrays; import java.util.Set; import java.util.UUID; @@ -58,7 +61,7 @@ public class VcnTest { private static final int PROVIDER_ID = 5; private static final int[][] TEST_CAPS = new int[][] { - new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS}, + new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET}, new int[] {NET_CAPABILITY_DUN} }; @@ -155,14 +158,6 @@ public class VcnTest { } } - @Test - public void testGatewayEnteringSafeModeNotifiesVcn() { - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { - startVcnGatewayWithCapabilities(requestListener, capability); - } - } - private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -188,8 +183,20 @@ public class VcnTest { return gatewayConnections; } + private void verifySafeMode( + NetworkRequestListener requestListener, + Set expectedGatewaysTornDown) { + assertFalse(mVcn.isActive()); + assertTrue(mVcn.getVcnGatewayConnections().isEmpty()); + for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { + verify(gatewayConnection).teardownAsynchronously(); + } + verify(mVcnNetworkProvider).unregisterListener(requestListener); + verify(mVcnCallback).onEnteredSafeMode(); + } + @Test - public void testGatewayEnteringSafemodeNotifiesVcn() { + public void testGatewayEnteringSafeModeNotifiesVcn() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final Set gatewayConnections = startGatewaysAndGetGatewayConnections(requestListener); @@ -200,12 +207,7 @@ public class VcnTest { statusCallback.onEnteredSafeMode(); mTestLooper.dispatchAll(); - assertFalse(mVcn.isActive()); - for (final VcnGatewayConnection gatewayConnection : gatewayConnections) { - verify(gatewayConnection).teardownAsynchronously(); - } - verify(mVcnNetworkProvider).unregisterListener(requestListener); - verify(mVcnCallback).onEnteredSafeMode(); + verifySafeMode(requestListener, gatewayConnections); } @Test @@ -234,4 +236,39 @@ public class VcnTest { any(), mGatewayStatusCallbackCaptor.capture()); } + + @Test + public void testUpdateConfigExitsSafeMode() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onEnteredSafeMode(); + mTestLooper.dispatchAll(); + verifySafeMode(requestListener, gatewayConnections); + + doAnswer(invocation -> { + final NetworkRequestListener listener = invocation.getArgument(0); + triggerVcnRequestListeners(listener); + return null; + }).when(mVcnNetworkProvider).registerListener(eq(requestListener)); + + mVcn.updateConfig(mConfig); + mTestLooper.dispatchAll(); + + // Registered on start, then re-registered with new configs + verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); + assertTrue(mVcn.isActive()); + for (final int[] caps : TEST_CAPS) { + // Expect each gateway connection created on initial startup, and again with new configs + verify(mDeps, times(2)) + .newVcnGatewayConnection( + eq(mVcnContext), + eq(TEST_SUB_GROUP), + eq(mSubscriptionSnapshot), + argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())), + any()); + } + } } From 5f09331bbcbf2530d1ed10518f7dfc448a89a855 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 24 Feb 2021 16:11:04 -0800 Subject: [PATCH 0119/1057] Use clean identity for all calls in/out of VcnMgmtSvc. This CL updates VcnManager and VcnManagementService to use a clean calling identify for handling all code paths entering and leaving the System Server. Bug: 180451994 Bug: 182183302 Test: atest FrameworksVcnTests Change-Id: I147408544531927ecaf5e40af6cb139342f5cd63 --- .../android/server/VcnManagementService.java | 115 ++++++++++-------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 0eca09e8d8..502e74a4cc 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -644,18 +644,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { android.Manifest.permission.NETWORK_FACTORY, "Must have permission NETWORK_FACTORY to register a policy listener"); - PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); + Binder.withCleanCallingIdentity(() -> { + PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); - synchronized (mLock) { - mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath); + synchronized (mLock) { + mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath); - try { - listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */); - } catch (RemoteException e) { - // Remote binder already died - cleanup registered Listener - listenerBinderDeath.binderDied(); + try { + listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */); + } catch (RemoteException e) { + // Remote binder already died - cleanup registered Listener + listenerBinderDeath.binderDied(); + } } - } + }); } /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ @@ -665,14 +667,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - synchronized (mLock) { - PolicyListenerBinderDeath listenerBinderDeath = - mRegisteredPolicyListeners.remove(listener.asBinder()); + Binder.withCleanCallingIdentity(() -> { + synchronized (mLock) { + PolicyListenerBinderDeath listenerBinderDeath = + mRegisteredPolicyListeners.remove(listener.asBinder()); - if (listenerBinderDeath != null) { - listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */); + if (listenerBinderDeath != null) { + listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */); + } } + }); + } + + private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) + && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { + TelephonyNetworkSpecifier telephonyNetworkSpecifier = + (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); + return telephonyNetworkSpecifier.getSubscriptionId(); + } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + && networkCapabilities.getTransportInfo() instanceof WifiInfo) { + WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); + return mDeps.getSubIdForWifiInfo(wifiInfo); } + + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } /** @@ -692,51 +711,47 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" + " Network policies"); - // Defensive copy in case this call is in-process and the given NetworkCapabilities mutates - networkCapabilities = new NetworkCapabilities(networkCapabilities); + return Binder.withCleanCallingIdentity(() -> { + // Defensive copy in case this call is in-process and the given NetworkCapabilities + // mutates + final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities); - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) - && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); - subId = telephonyNetworkSpecifier.getSubscriptionId(); - } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) - && networkCapabilities.getTransportInfo() instanceof WifiInfo) { - WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - subId = mDeps.getSubIdForWifiInfo(wifiInfo); - } + final int subId = getSubIdForNetworkCapabilities(ncCopy); + boolean isVcnManagedNetwork = false; + boolean isRestrictedCarrierWifi = false; + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + synchronized (mLock) { + ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); - boolean isVcnManagedNetwork = false; - boolean isRestrictedCarrierWifi = false; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - synchronized (mLock) { - ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); + final Vcn vcn = mVcns.get(subGroup); + if (vcn != null) { + if (vcn.isActive()) { + isVcnManagedNetwork = true; + } - Vcn vcn = mVcns.get(subGroup); - if (vcn != null) { - if (vcn.isActive()) { - isVcnManagedNetwork = true; - } - - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - // Carrier WiFi always restricted if VCN exists (even in safe mode). - isRestrictedCarrierWifi = true; + if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + // Carrier WiFi always restricted if VCN exists (even in safe mode). + isRestrictedCarrierWifi = true; + } } } } - } - if (isVcnManagedNetwork) { - networkCapabilities.removeCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(ncCopy); - if (isRestrictedCarrierWifi) { - networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } + if (isVcnManagedNetwork) { + ncBuilder.removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } - return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); + if (isRestrictedCarrierWifi) { + ncBuilder.removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + + return new VcnUnderlyingNetworkPolicy( + false /* isTearDownRequested */, ncBuilder.build()); + }); } /** Binder death recipient used to remove registered VcnStatusCallbacks. */ From 769f8c2e67c0406fa4b1bc917fd334eb1781fc31 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Mar 2021 17:46:46 +0900 Subject: [PATCH 0120/1057] Move LocationPermissionChecker to libs/net LocationPermissionChecker was written to be used by multiple connectivity modules, so it belongs in the frameworks/libs/net library. The file is moved as-is with minor modifications in the test to avoid usage of the privileged ActivityManager.getCurrentUser API. Bug: 181837977 Test: atest NetworkStaticLibTests Change-Id: I63bce35ba87c45138b3aaf6244367e982dfec455 --- Vcn/service-b/src/com/android/server/VcnManagementService.java | 2 +- .../unit/java/com/android/server/VcnManagementServiceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 502e74a4cc..a9e902a6d0 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -64,7 +64,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.LocationPermissionChecker; +import com.android.net.module.util.LocationPermissionChecker; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 11498dec81..ad459bf700 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -74,7 +74,7 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.util.LocationPermissionChecker; +import com.android.net.module.util.LocationPermissionChecker; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnStatusCallbackInfo; import com.android.server.vcn.TelephonySubscriptionTracker; From bc5376e825e81dab894a25f88701011fb5bb3621 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Mar 2021 11:31:59 -0800 Subject: [PATCH 0121/1057] Remove usage of hidden Connectivity APIs This removes one use of NetworkRequest.requestId, and the usage of the NetCapability intdef Bug: 170598012 Test: atest FrameworksVcnTests Change-Id: I6b688b008721bc9f5cb1435f2e7096277a12dc45 --- .../src/com/android/server/vcn/UnderlyingNetworkTracker.java | 3 +-- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index b2db9f5af0..754065920b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -23,7 +23,6 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.Handler; @@ -133,7 +132,7 @@ public class UnderlyingNetworkTracker { private NetworkRequest.Builder getNetworkRequestBase() { NetworkRequest.Builder requestBase = new NetworkRequest.Builder(); - for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) { + for (int capability : mRequiredUnderlyingNetworkCapabilities) { requestBase.addCapability(capability); } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 9d39c67d27..e83fe802e1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -291,9 +291,7 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.v( - getLogTag(), - "Bringing up new VcnGatewayConnection for request " + request.requestId); + Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( From 000773fb8165a4ca789704afa057acda0baed6e5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 9 Mar 2021 11:02:36 -0800 Subject: [PATCH 0122/1057] Specify exposed capabilities for VCN gateway connection errors. This CL updates VCN error callbacks to return the exposed capabilities for a gateway connection for identification purposes. Previously, the required underlying capabilities were returned (which are not meaningful to the caller for identification purposes). Bug: 182281888 Test: atest FrameworksVcnTests Change-Id: Ic62bd0b524f24f2577d9abc7635112a6419d35ed --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 4 ++-- .../server/vcn/VcnGatewayConnectionConnectedStateTest.java | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 6bc9978a07..15429f455d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -979,7 +979,7 @@ public class VcnGatewayConnection extends StateMachine { // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed() if (exception != null) { mGatewayStatusCallback.onGatewayConnectionError( - mConnectionConfig.getRequiredUnderlyingCapabilities(), + mConnectionConfig.getExposedCapabilities(), VCN_ERROR_CODE_INTERNAL_ERROR, RuntimeException.class.getName(), "Received " @@ -1016,7 +1016,7 @@ public class VcnGatewayConnection extends StateMachine { } mGatewayStatusCallback.onGatewayConnectionError( - mConnectionConfig.getRequiredUnderlyingCapabilities(), + mConnectionConfig.getExposedCapabilities(), errorCode, exceptionClass, exceptionMessage); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 69b2fb135a..4bf849111a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -241,7 +241,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mGatewayStatusCallback) .onGatewayConnectionError( - eq(mConfig.getRequiredUnderlyingCapabilities()), + eq(mConfig.getExposedCapabilities()), eq(VCN_ERROR_CODE_INTERNAL_ERROR), any(), any()); @@ -275,10 +275,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mGatewayStatusCallback) .onGatewayConnectionError( - eq(mConfig.getRequiredUnderlyingCapabilities()), - eq(expectedErrorType), - any(), - any()); + eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any()); } @Test From 051924b86496913a11b8c6cd2985bbcc7e924389 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Mar 2021 11:36:46 -0800 Subject: [PATCH 0123/1057] Override network and use config IKE session This change ensures the IKE configs are used with the correct network Bug: 163604823 Test: FrameworksVcnTests Change-Id: Ieb2a9b202204577f6e6969ef30245baed6382aa6 --- .../server/vcn/VcnGatewayConnection.java | 23 ++++++++++++------- ...cnGatewayConnectionConnectedStateTest.java | 2 +- ...nGatewayConnectionConnectingStateTest.java | 10 +++++++- ...tewayConnectionDisconnectingStateTest.java | 3 ++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 6bc9978a07..803191e43e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -59,6 +59,7 @@ import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; @@ -1348,7 +1349,7 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = null; } - mIkeSession = buildIkeSession(); + mIkeSession = buildIkeSession(mUnderlying.network); } @Override @@ -1939,23 +1940,29 @@ public class VcnGatewayConnection extends StateMachine { new EventDisconnectRequestedInfo(reason, shouldQuit)); } - private IkeSessionParams buildIkeParams() { - // TODO: Implement this once IkeSessionParams is persisted - return null; + private IkeSessionParams buildIkeParams(@NonNull Network network) { + final VcnControlPlaneIkeConfig controlPlaneConfig = + (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams()); + builder.setConfiguredNetwork(network); + + return builder.build(); } private ChildSessionParams buildChildParams() { - // TODO: Implement this once IkeSessionParams is persisted - return null; + final VcnControlPlaneIkeConfig controlPlaneConfig = + (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); + return controlPlaneConfig.getChildSessionParams(); } @VisibleForTesting(visibility = Visibility.PRIVATE) - VcnIkeSession buildIkeSession() { + VcnIkeSession buildIkeSession(@NonNull Network network) { final int token = ++mCurrentToken; return mDeps.newIkeSession( mVcnContext, - buildIkeParams(), + buildIkeParams(network), buildChildParams(), new IkeSessionCallbackImpl(token), new VcnChildSessionCallback(token)); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 69b2fb135a..bfa869edf0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -73,7 +73,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); - mIkeSession = mGatewayConnection.buildIkeSession(); + mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); mGatewayConnection.setIkeSession(mIkeSession); mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index d07d2cf4f1..7afa4494ee 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -25,12 +25,15 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.net.ipsec.ike.IkeSessionParams; + 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; /** Tests for VcnGatewayConnection.ConnectingState */ @RunWith(AndroidJUnit4.class) @@ -51,7 +54,12 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio @Test public void testEnterStateCreatesNewIkeSession() throws Exception { - verify(mDeps).newIkeSession(any(), any(), any(), any(), any()); + final ArgumentCaptor paramsCaptor = + ArgumentCaptor.forClass(IkeSessionParams.class); + verify(mDeps).newIkeSession(any(), paramsCaptor.capture(), any(), any(), any()); + assertEquals( + TEST_UNDERLYING_NETWORK_RECORD_1.network, + paramsCaptor.getValue().getConfiguredNetwork()); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 661e03af4f..99feffdebc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -38,7 +38,8 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec public void setUp() throws Exception { super.setUp(); - mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession()); + mGatewayConnection.setIkeSession( + mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_2.network)); // ensure that mGatewayConnection has an underlying Network before entering // DisconnectingState From 07f0359c89391a5047fb2890207700d30fac21ed Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 3 Mar 2021 11:28:22 -0800 Subject: [PATCH 0124/1057] Update Policy Listener API naming. This CL changes the policy listener API to be VcnNetworkPolicyChangeListener (it was previously VcnNetworkPolicyListener) per API Council guidance. This CL also requires permission NETWORK_FACTORY for removing registered policy listeners. Bug: 181562364 Test: atest FrameworksVcnTests Change-Id: I026eaefa62d8f64b9180fc182a7cf0605d83bf97 --- .../src/android/net/vcn/VcnManager.java | 65 ++++++++++--------- .../android/server/VcnManagementService.java | 4 ++ .../server/VcnManagementServiceTest.java | 10 +++ 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 8ebf757760..062438c6e5 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -73,7 +73,8 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map + private static final Map< + VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +94,13 @@ public class VcnManager { } /** - * Get all currently registered VcnNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map + public static Map getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -162,14 +163,14 @@ public class VcnManager { } // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using - // the new VcnNetworkPolicyListener API + // the new VcnNetworkPolicyChangeListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {} /** * Add a listener for VCN-underlying network policy updates. @@ -185,7 +186,7 @@ public class VcnManager { @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnUnderlyingNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { - addVcnNetworkPolicyListener(executor, listener); + addVcnNetworkPolicyChangeListener(executor, listener); } /** @@ -198,7 +199,7 @@ public class VcnManager { */ public void removeVcnUnderlyingNetworkPolicyListener( @NonNull VcnUnderlyingNetworkPolicyListener listener) { - removeVcnNetworkPolicyListener(listener); + removeVcnNetworkPolicyChangeListener(listener); } /** @@ -233,20 +234,20 @@ public class VcnManager { } /** - * VcnNetworkPolicyListener is the interface through which internal system components (e.g. - * Network Factories) can register to receive updates for VCN-underlying Network policies from - * the System Server. + * VcnNetworkPolicyChangeListener is the interface through which internal system components + * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies + * from the System Server. * *

    Any Network Factory that brings up Networks capable of being VCN-underlying Networks - * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify - * the registrant when VCN Network policies change. Upon receiving this signal, the listener - * must check {@link VcnManager} for the current Network policy result for each of its Networks - * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to + * notify the registrant when VCN Network policies change. Upon receiving this signal, the + * listener must check {@link VcnManager} for the current Network policy result for each of its + * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. * * @hide */ @SystemApi - public interface VcnNetworkPolicyListener { + public interface VcnNetworkPolicyChangeListener { /** * Notifies the implementation that the VCN's underlying Network policy has changed. * @@ -260,20 +261,21 @@ public class VcnManager { /** * Add a listener for VCN-underlying Network policy updates. * - *

    A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is - * registered. No callbacks are guaranteed upon registration. + *

    A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it + * is registered. No callbacks are guaranteed upon registration. * * @param executor the Executor that will be used for invoking all calls to the specified * Listener - * @param listener the VcnNetworkPolicyListener to be added + * @param listener the VcnNetworkPolicyChangeListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered + * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already + * registered * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public void addVcnNetworkPolicyListener( - @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { + public void addVcnNetworkPolicyChangeListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(executor, "executor must not be null"); requireNonNull(listener, "listener must not be null"); @@ -292,15 +294,18 @@ public class VcnManager { } /** - * Remove the specified VcnNetworkPolicyListener from VcnManager. + * Remove the specified VcnNetworkPolicyChangeListener from VcnManager. * *

    If the specified listener is not currently registered, this is a no-op. * - * @param listener the VcnNetworkPolicyListener that will be removed + * @param listener the VcnNetworkPolicyChangeListener that will be removed + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY * @hide */ @SystemApi - public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void removeVcnNetworkPolicyChangeListener( + @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(listener, "listener must not be null"); VcnUnderlyingNetworkPolicyListenerBinder binder = @@ -320,8 +325,9 @@ public class VcnManager { * Applies the network policy for a {@link android.net.Network} with the given parameters. * *

    Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy - * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider - * MUST poll for the updated Network policy based on that Network's capabilities and properties. + * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network + * Provider MUST poll for the updated Network policy based on that Network's capabilities and + * properties. * * @param networkCapabilities the NetworkCapabilities to be used in determining the Network * policy result for this Network. @@ -532,17 +538,18 @@ public class VcnManager { } /** - * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. + * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System + * Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyChangeListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyChangeListener listener) { mExecutor = executor; mListener = listener; } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index cd3892da43..140f24f7cf 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -666,6 +666,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_FACTORY, + "Must have permission NETWORK_FACTORY to unregister a policy listener"); + Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { PolicyListenerBinderDeath listenerBinderDeath = diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 11498dec81..a02002752c 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -593,6 +593,16 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } + @Test(expected = SecurityException.class) + public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() { + doThrow(new SecurityException()) + .when(mMockContext) + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } + @Test public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); From 642dff7ba535339b665699355d25829235d4da72 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 9 Mar 2021 14:44:19 -0800 Subject: [PATCH 0125/1057] Use updated API for VCN Network policy listeners. This CL updates CTS testing for VcnManager to test the updated API for VcnNetworkPolicyChangeListener (renamed from VcnNetworkPolicyListener), per API Council guidance. Bug: 181562364 Test: atest CtsVcnTestCases Change-Id: Iad2f48d6b4dcf129724e73922ed681f3136db7b5 --- .../android/net/vcn/cts/VcnManagerTest.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index a5646fa1f6..81e0a015cd 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -186,9 +186,9 @@ public class VcnManagerTest { }); } - /** Test implementation of VcnNetworkPolicyListener for verification purposes. */ - private static class TestVcnNetworkPolicyListener - implements VcnManager.VcnNetworkPolicyListener { + /** Test implementation of VcnNetworkPolicyChangeListener for verification purposes. */ + private static class TestVcnNetworkPolicyChangeListener + implements VcnManager.VcnNetworkPolicyChangeListener { private final CompletableFuture mFutureOnPolicyChanged = new CompletableFuture<>(); @Override @@ -202,21 +202,24 @@ public class VcnManagerTest { } @Test(expected = SecurityException.class) - public void testAddVcnNetworkPolicyListener_noNetworkFactoryPermission() throws Exception { - final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() + throws Exception { + final TestVcnNetworkPolicyChangeListener listener = + new TestVcnNetworkPolicyChangeListener(); try { - mVcnManager.addVcnNetworkPolicyListener(INLINE_EXECUTOR, listener); + mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, listener); } finally { - mVcnManager.removeVcnNetworkPolicyListener(listener); + mVcnManager.removeVcnNetworkPolicyChangeListener(listener); } } @Test - public void testRemoveVcnNetworkPolicyListener() { - final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + public void testRemoveVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() { + final TestVcnNetworkPolicyChangeListener listener = + new TestVcnNetworkPolicyChangeListener(); - mVcnManager.removeVcnNetworkPolicyListener(listener); + mVcnManager.removeVcnNetworkPolicyChangeListener(listener); } @Test(expected = SecurityException.class) From c88d2037c8af8fb65425b3ec00b8e2e99fccd87b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Mar 2021 15:26:58 -0800 Subject: [PATCH 0126/1057] Allow underlying cell without unwanted NOT_VCN_MANAGED capability This change updates the UnderlyingNetworkTracker to rely on the TelephonyNetworkSpecifier for selecting underlying networks. This ensures that there is always a cellular NetworkRequest filed for Cellular to bring up an underlying Network. Bug: 182211364 Test: FrameworksVcnTests Change-Id: I826711bb671440054c2090793315a5f1d57596c0 --- .../server/vcn/UnderlyingNetworkTracker.java | 50 +++++++++++++++---- .../vcn/UnderlyingNetworkTrackerTest.java | 26 ++++++---- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 754065920b..8dcc547508 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -114,33 +114,61 @@ public class UnderlyingNetworkTracker { getWifiNetworkRequest(), mHandler, mWifiBringupCallback); updateSubIdsAndCellularRequests(); - // register Network-selection request used to decide selected underlying Network + // Register Network-selection request used to decide selected underlying Network. All + // underlying networks must be VCN managed in order to be used. mConnectivityManager.requestBackgroundNetwork( - getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback); + getBaseNetworkRequest(true /* requireVcnManaged */).build(), + mHandler, + mRouteSelectionCallback); } private NetworkRequest getWifiNetworkRequest() { - return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi + // alive. + return getBaseNetworkRequest(true /* requireVcnManaged */) + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); } private NetworkRequest getCellNetworkRequestForSubId(int subId) { - return getNetworkRequestBase() + // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a + // fulfillable request to bring up underlying cellular Networks even if the VCN is already + // connected. + return getBaseNetworkRequest(false /* requireVcnManaged */) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } - private NetworkRequest.Builder getNetworkRequestBase() { - NetworkRequest.Builder requestBase = new NetworkRequest.Builder(); + /** + * Builds and returns a NetworkRequest builder common to all Underlying Network requests + * + *

    A NetworkRequest may either (1) Require the presence of a capability by using + * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3) + * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED + * capability, and only cases (2) and (3) are used. + * + * @param requireVcnManaged whether the underlying network is required to be VCN managed to + * match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as + * unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is + * acceptable. + */ + private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) { + NetworkRequest.Builder requestBase = + new NetworkRequest.Builder() + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + for (int capability : mRequiredUnderlyingNetworkCapabilities) { requestBase.addCapability(capability); } - return requestBase - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + if (requireVcnManaged) { + requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + return requestBase; } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1d459a3475..1ef1a61f17 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -194,29 +194,35 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getWifiRequest() { - return getExpectedRequestBase() + return getExpectedRequestBase(true) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } private NetworkRequest getCellRequestForSubId(int subId) { - return getExpectedRequestBase() + return getExpectedRequestBase(false) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } private NetworkRequest getRouteSelectionRequest() { - return getExpectedRequestBase().build(); + return getExpectedRequestBase(true).build(); } - private NetworkRequest.Builder getExpectedRequestBase() { - return new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) { + final NetworkRequest.Builder builder = + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + + if (requireVcnManaged) { + builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + return builder; } @Test From 42cd57b41a737571c3f89f5c02f66606073c31c9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Mar 2021 16:08:41 -0800 Subject: [PATCH 0127/1057] Declare VCN exposed networks as NOT_VCN_MANAGED This change marks VCN-exposed networks as generic use, NOT_VCN_MANAGED networks. This is the result of changes to the default NetworkCapability set, where NOT_VCN_MANAGED was removed from the default capabilities. Bug: 182212201 Test: atest FrameworksVcnTests Change-Id: Iad296830201d7317537fac6bea53c79d4e41cae3 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 ++ .../java/com/android/server/vcn/VcnGatewayConnectionTest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 803191e43e..55b1808a0d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; @@ -1727,6 +1728,7 @@ public class VcnGatewayConnection extends StateMachine { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); + builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); builder.addCapability(NET_CAPABILITY_NOT_CONGESTED); builder.addCapability(NET_CAPABILITY_NOT_SUSPENDED); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 748c792468..d08af9dd33 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -18,6 +18,7 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -87,6 +88,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private void verifyBuildNetworkCapabilitiesCommon(int transportType) { final NetworkCapabilities underlyingCaps = new NetworkCapabilities(); underlyingCaps.addTransportType(transportType); + underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED); underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING); From d82709bbe2b5256c79424af70098d51892670915 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 9 Mar 2021 14:44:19 -0800 Subject: [PATCH 0128/1057] Use updated API for VCN Network policy listeners. This CL updates CTS testing for VcnManager to test the updated API for VcnNetworkPolicyChangeListener (renamed from VcnNetworkPolicyListener), per API Council guidance. Bug: 181562364 Test: atest CtsVcnTestCases Change-Id: Iad2f48d6b4dcf129724e73922ed681f3136db7b5 Merged-In: Iad2f48d6b4dcf129724e73922ed681f3136db7b5 (cherry picked from commit 642dff7ba535339b665699355d25829235d4da72) --- .../android/net/vcn/cts/VcnManagerTest.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index a5646fa1f6..81e0a015cd 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -186,9 +186,9 @@ public class VcnManagerTest { }); } - /** Test implementation of VcnNetworkPolicyListener for verification purposes. */ - private static class TestVcnNetworkPolicyListener - implements VcnManager.VcnNetworkPolicyListener { + /** Test implementation of VcnNetworkPolicyChangeListener for verification purposes. */ + private static class TestVcnNetworkPolicyChangeListener + implements VcnManager.VcnNetworkPolicyChangeListener { private final CompletableFuture mFutureOnPolicyChanged = new CompletableFuture<>(); @Override @@ -202,21 +202,24 @@ public class VcnManagerTest { } @Test(expected = SecurityException.class) - public void testAddVcnNetworkPolicyListener_noNetworkFactoryPermission() throws Exception { - final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() + throws Exception { + final TestVcnNetworkPolicyChangeListener listener = + new TestVcnNetworkPolicyChangeListener(); try { - mVcnManager.addVcnNetworkPolicyListener(INLINE_EXECUTOR, listener); + mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, listener); } finally { - mVcnManager.removeVcnNetworkPolicyListener(listener); + mVcnManager.removeVcnNetworkPolicyChangeListener(listener); } } @Test - public void testRemoveVcnNetworkPolicyListener() { - final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener(); + public void testRemoveVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() { + final TestVcnNetworkPolicyChangeListener listener = + new TestVcnNetworkPolicyChangeListener(); - mVcnManager.removeVcnNetworkPolicyListener(listener); + mVcnManager.removeVcnNetworkPolicyChangeListener(listener); } @Test(expected = SecurityException.class) From 36099b1871f6a27fd84d2f322cc71e92a9b4b79a Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 3 Mar 2021 11:28:22 -0800 Subject: [PATCH 0129/1057] Update Policy Listener API naming. This CL changes the policy listener API to be VcnNetworkPolicyChangeListener (it was previously VcnNetworkPolicyListener) per API Council guidance. This CL also requires permission NETWORK_FACTORY for removing registered policy listeners. Bug: 181562364 Test: atest FrameworksVcnTests Change-Id: I026eaefa62d8f64b9180fc182a7cf0605d83bf97 Merged-In: I026eaefa62d8f64b9180fc182a7cf0605d83bf97 (cherry picked from commit 07f0359c89391a5047fb2890207700d30fac21ed) --- .../src/android/net/vcn/VcnManager.java | 65 ++++++++++--------- .../android/server/VcnManagementService.java | 4 ++ .../server/VcnManagementServiceTest.java | 10 +++ 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 8ebf757760..062438c6e5 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -73,7 +73,8 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map + private static final Map< + VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +94,13 @@ public class VcnManager { } /** - * Get all currently registered VcnNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map + public static Map getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -162,14 +163,14 @@ public class VcnManager { } // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using - // the new VcnNetworkPolicyListener API + // the new VcnNetworkPolicyChangeListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {} /** * Add a listener for VCN-underlying network policy updates. @@ -185,7 +186,7 @@ public class VcnManager { @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnUnderlyingNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { - addVcnNetworkPolicyListener(executor, listener); + addVcnNetworkPolicyChangeListener(executor, listener); } /** @@ -198,7 +199,7 @@ public class VcnManager { */ public void removeVcnUnderlyingNetworkPolicyListener( @NonNull VcnUnderlyingNetworkPolicyListener listener) { - removeVcnNetworkPolicyListener(listener); + removeVcnNetworkPolicyChangeListener(listener); } /** @@ -233,20 +234,20 @@ public class VcnManager { } /** - * VcnNetworkPolicyListener is the interface through which internal system components (e.g. - * Network Factories) can register to receive updates for VCN-underlying Network policies from - * the System Server. + * VcnNetworkPolicyChangeListener is the interface through which internal system components + * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies + * from the System Server. * *

    Any Network Factory that brings up Networks capable of being VCN-underlying Networks - * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify - * the registrant when VCN Network policies change. Upon receiving this signal, the listener - * must check {@link VcnManager} for the current Network policy result for each of its Networks - * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to + * notify the registrant when VCN Network policies change. Upon receiving this signal, the + * listener must check {@link VcnManager} for the current Network policy result for each of its + * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. * * @hide */ @SystemApi - public interface VcnNetworkPolicyListener { + public interface VcnNetworkPolicyChangeListener { /** * Notifies the implementation that the VCN's underlying Network policy has changed. * @@ -260,20 +261,21 @@ public class VcnManager { /** * Add a listener for VCN-underlying Network policy updates. * - *

    A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is - * registered. No callbacks are guaranteed upon registration. + *

    A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it + * is registered. No callbacks are guaranteed upon registration. * * @param executor the Executor that will be used for invoking all calls to the specified * Listener - * @param listener the VcnNetworkPolicyListener to be added + * @param listener the VcnNetworkPolicyChangeListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered + * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already + * registered * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public void addVcnNetworkPolicyListener( - @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { + public void addVcnNetworkPolicyChangeListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(executor, "executor must not be null"); requireNonNull(listener, "listener must not be null"); @@ -292,15 +294,18 @@ public class VcnManager { } /** - * Remove the specified VcnNetworkPolicyListener from VcnManager. + * Remove the specified VcnNetworkPolicyChangeListener from VcnManager. * *

    If the specified listener is not currently registered, this is a no-op. * - * @param listener the VcnNetworkPolicyListener that will be removed + * @param listener the VcnNetworkPolicyChangeListener that will be removed + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY * @hide */ @SystemApi - public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void removeVcnNetworkPolicyChangeListener( + @NonNull VcnNetworkPolicyChangeListener listener) { requireNonNull(listener, "listener must not be null"); VcnUnderlyingNetworkPolicyListenerBinder binder = @@ -320,8 +325,9 @@ public class VcnManager { * Applies the network policy for a {@link android.net.Network} with the given parameters. * *

    Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy - * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider - * MUST poll for the updated Network policy based on that Network's capabilities and properties. + * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network + * Provider MUST poll for the updated Network policy based on that Network's capabilities and + * properties. * * @param networkCapabilities the NetworkCapabilities to be used in determining the Network * policy result for this Network. @@ -532,17 +538,18 @@ public class VcnManager { } /** - * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. + * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System + * Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyChangeListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyChangeListener listener) { mExecutor = executor; mListener = listener; } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 502e74a4cc..1ef93f4da2 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -667,6 +667,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_FACTORY, + "Must have permission NETWORK_FACTORY to unregister a policy listener"); + Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { PolicyListenerBinderDeath listenerBinderDeath = diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 11498dec81..a02002752c 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -593,6 +593,16 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } + @Test(expected = SecurityException.class) + public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() { + doThrow(new SecurityException()) + .when(mMockContext) + .enforceCallingOrSelfPermission( + eq(android.Manifest.permission.NETWORK_FACTORY), any()); + + mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + } + @Test public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); From 25d67f9971471aaa1238e00a4a6f03cd96cb6ed6 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 11 Mar 2021 15:45:59 -0800 Subject: [PATCH 0130/1057] Use updated VcnStatusCallback API. This CL updates CTS testing for VcnManager to use VcnStatusCallback#onStatusChanged following feedback from the API Council. Bug: 182345902 Test: atest CtsVcnTestCases Change-Id: I2e20ccf041af519e1e44a563fadc3ca6c148df05 --- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index a5646fa1f6..921a4d8fcd 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -229,14 +229,14 @@ public class VcnManagerTest { /** Test implementation of VcnStatusCallback for verification purposes. */ private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { - private final CompletableFuture mFutureOnVcnStatusChanged = + private final CompletableFuture mFutureOnStatusChanged = new CompletableFuture<>(); private final CompletableFuture mFutureOnGatewayConnectionError = new CompletableFuture<>(); @Override - public void onVcnStatusChanged(int statusCode) { - mFutureOnVcnStatusChanged.complete(statusCode); + public void onStatusChanged(int statusCode) { + mFutureOnStatusChanged.complete(statusCode); } @Override @@ -246,8 +246,8 @@ public class VcnManagerTest { new GatewayConnectionError(networkCapabilities, errorCode, detail)); } - public int awaitOnVcnStatusChanged() throws Exception { - return mFutureOnVcnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + public int awaitOnStatusChanged() throws Exception { + return mFutureOnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); } public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception { @@ -286,7 +286,7 @@ public class VcnManagerTest { try { registerVcnStatusCallbackForSubId(callback, subId); - final int statusCode = callback.awaitOnVcnStatusChanged(); + final int statusCode = callback.awaitOnStatusChanged(); assertEquals(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED, statusCode); } finally { mVcnManager.unregisterVcnStatusCallback(callback); From ce6804db4374e2dd19ea535151d3c0b121fc06ad Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 21 Dec 2020 18:36:52 +0900 Subject: [PATCH 0131/1057] [NS01] Add NetworkScore As attested by numerous TODOs in the code, a new way of representing network quality and policy is needed instead of an int. An int representing the quality of the network requires all parties using it to know how all other parties are using it, and implementation details about the decision algorithm. For all intents and purposes, the selection is left to individual network factories who try to achieve a desired result while piecing together all possible states of the system. As the number of such cases and desires increases, this becomes both intractable and unmaintainable. Indeed, at this time in the codebase nobody can really predict exactly how a given change in score will affect selection across the board, and it is essentially impossible to figure out the behavior of network selection by inspecting the code because the moving parts are scattered throughout the entire codebase. Having an object encapsulating policy and quality values will let us centralize the selection and make it again possible to maintain without knowledge of all behaviors of all network factories. It will also provide better guarantees of respecting policy, and allow bugfixes that were not possible before because they'd touch too many parts of the code. Test: FrameworksNetTests FrameworksWifiTests NetworkStackTests Change-Id: I3185a6412b9b659798faf0c6882699e9c63cc115 --- .../server/vcn/VcnGatewayConnectionConnectedStateTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 0e5f5e43f2..ca6448ca9b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -188,7 +188,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), lpCaptor.capture(), ncCaptor.capture(), - anyInt(), + any(), any(), anyInt()); verify(mIpSecSvc) From f1b29cb6bfbf0c19b0936b2e24904e5bdd2b2dc4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 12 Mar 2021 16:12:58 -0800 Subject: [PATCH 0132/1057] Hide required underlying caps APIs VCN underlying network capabilities should be transport-dependent in order to allow using anything other than the INTERNET capability for VCN types that support wifi offload. Specifically, if underlying network capabilities are not transport-dependent, and Wifi only ever supports the INTERNET capability, the VCN is unable to utilize wifi offload together with requiring NET_CAPABILITY_IMS or NET_CAPABILITY_CBS, since the IMS or CBS capability would be required for both cellular and wifi underlying networks. Until such time as a per-transport capability set is allowed, hide the exposedCapability pieces, and document that all underlying networks MUST have INTERNET capability in order to be used. Bug: 182219992 Test: atest FrameworksVcnTests Test: atest CtsVcnTestCases Change-Id: I50d7f1be42e0e001f1413a3d5fe8aa4b7afec223 --- .../net/vcn/VcnGatewayConnectionConfig.java | 22 +++++++++---------- .../src/android/net/vcn/VcnManager.java | 2 +- .../vcn/VcnGatewayConnectionConfigTest.java | 10 --------- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 9f83b21f0d..d4e8e2dca2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -52,13 +52,12 @@ import java.util.concurrent.TimeUnit; * Network}s. * *

    A VCN connection based on this configuration will be brought up dynamically based on device - * settings, and filed NetworkRequests. Underlying networks will be selected based on the services - * required by this configuration (as represented by network capabilities), and must be part of the - * subscription group under which this configuration is registered (see {@link + * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and + * must be part of the subscription group under which this configuration is registered (see {@link * VcnManager#setVcnConfig}). * - *

    As an abstraction of a cellular network, services that can be provided by a VCN network, or - * required for underlying networks are limited to services provided by cellular networks: + *

    As an abstraction of a cellular network, services that can be provided by a VCN network are + * limited to services provided by cellular networks: * *

      *
    • {@link NetworkCapabilities#NET_CAPABILITY_MMS} @@ -214,13 +213,6 @@ public final class VcnGatewayConnectionConfig { checkValidCapability(cap); } - Preconditions.checkArgument( - mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(), - "underlyingCapabilities was null or empty"); - for (Integer cap : getAllUnderlyingCapabilities()) { - checkValidCapability(cap); - } - Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); validateRetryInterval(mRetryIntervalsMs); @@ -295,7 +287,9 @@ public final class VcnGatewayConnectionConfig { * * @see Builder#addRequiredUnderlyingCapability(int) * @see Builder#removeRequiredUnderlyingCapability(int) + * @hide */ + // TODO(b/182219992): Remove, and add when per-transport capabilities are supported @NonNull public int[] getRequiredUnderlyingCapabilities() { // Sorted set guarantees ordering @@ -470,7 +464,9 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ + // TODO(b/182219992): Remove, and add when per-transport capabilities are supported @NonNull public Builder addRequiredUnderlyingCapability( @VcnSupportedCapability int underlyingCapability) { @@ -492,7 +488,9 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ + // TODO(b/182219992): Remove, and add when per-transport capabilities are supported @NonNull @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap public Builder removeRequiredUnderlyingCapability( diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 062438c6e5..b73fdbff8e 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -448,7 +448,7 @@ public class VcnManager { * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities * for the Gateway Connection that encountered the error, for identification purposes. * These will be a sorted list with no duplicates and will match {@link - * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link + * VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription * group. * @param errorCode the code to indicate the error that occurred diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 5b17aadc50..8a0c923d5f 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -108,16 +108,6 @@ public class VcnGatewayConnectionConfigTest { } } - @Test - public void testBuilderRequiresNonEmptyUnderlyingCaps() { - try { - newBuilder().addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build(); - - fail("Expected exception due to invalid required underlying capabilities"); - } catch (IllegalArgumentException e) { - } - } - @Test public void testBuilderRequiresNonNullRetryInterval() { try { From 3ee8683c0ebeb01d82d056fe43f6234477ca472d Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:42:46 +0800 Subject: [PATCH 0133/1057] Remove reference of @ValidationStatus annotation This is hidden and no longer accessible after ConnectivityService becomes mainline module. Test: TH Bug: 182963397 Change-Id: Iaba678ed3af92f87cfeccaacf1cc5723c8e5dcae --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 69a153f79a..516426558d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -42,7 +42,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; -import android.net.NetworkAgent.ValidationStatus; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; @@ -1451,8 +1450,7 @@ public class VcnGatewayConnection extends StateMachine { } @Override - public void onValidationStatus( - @ValidationStatus int status, @Nullable Uri redirectUri) { + public void onValidationStatus(int status, @Nullable Uri redirectUri) { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { clearFailedAttemptCounterAndSafeModeAlarm(); } From 91b1583485cd4720250ff71b8159d6d86a231207 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:58:46 +0800 Subject: [PATCH 0134/1057] Remove references of NetworkAgentConfig constructor This is hidden, use public Builder instead. Test: TH Bug: 182963397 Change-Id: Ib8ea2a17276cfd000e7003fc86d15458e1f82b39 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 516426558d..84bc6a8056 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1441,7 +1441,7 @@ public class VcnGatewayConnection extends StateMachine { caps, lp, Vcn.getNetworkScore(), - new NetworkAgentConfig(), + new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override public void unwanted() { From d64feabf88b23fecf9776d8ecd916aa00537372d Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 15:12:37 +0800 Subject: [PATCH 0135/1057] Remove reference of NetworkAgent#unwanted() This is hidden, use onNetworkUnwanted instead. Test: TH Bug: 182963397 Change-Id: I4e80a75d25cfd9ffc07aa219fff5a2604eb307f2 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 84bc6a8056..673618b607 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1444,7 +1444,7 @@ public class VcnGatewayConnection extends StateMachine { new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override - public void unwanted() { + public void onNetworkUnwanted() { Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } From 65b51d4cf8cc52632b408ab9f747fb8f81fbb256 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 15:37:54 +0800 Subject: [PATCH 0136/1057] Remove hidden API usage of RouteInfo For callers who use hidden constructor of RouteInfo, replace them with public constructor. Test: TH Bug: 182963397 Change-Id: I18d2cceafad633a95bd909b7f693d45e8a861bc9 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 673618b607..9589505ef2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1796,8 +1796,10 @@ public class VcnGatewayConnection extends StateMachine { lp.addDnsServer(addr); } - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); - lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); lp.setMtu(gatewayConnectionConfig.getMaxMtu()); From 7a4f0cc1ee543ab309d00e3c32f10c8fa3fb504c Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:42:46 +0800 Subject: [PATCH 0137/1057] Remove reference of @ValidationStatus annotation This is hidden and no longer accessible after ConnectivityService becomes mainline module. Test: TH Bug: 182963397 Merged-In: Iaba678ed3af92f87cfeccaacf1cc5723c8e5dcae Change-Id: Iaba678ed3af92f87cfeccaacf1cc5723c8e5dcae (cherry-picked from ag/13925161) --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 69a153f79a..516426558d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -42,7 +42,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; -import android.net.NetworkAgent.ValidationStatus; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; @@ -1451,8 +1450,7 @@ public class VcnGatewayConnection extends StateMachine { } @Override - public void onValidationStatus( - @ValidationStatus int status, @Nullable Uri redirectUri) { + public void onValidationStatus(int status, @Nullable Uri redirectUri) { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { clearFailedAttemptCounterAndSafeModeAlarm(); } From 5b7dc591fb6be883c9b766aba3899189b873268c Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:58:46 +0800 Subject: [PATCH 0138/1057] Remove references of NetworkAgentConfig constructor This is hidden, use public Builder instead. Test: TH Bug: 182963397 Merged-In: Ib8ea2a17276cfd000e7003fc86d15458e1f82b39 Change-Id: Ib8ea2a17276cfd000e7003fc86d15458e1f82b39 (cherry-picked from ag/13925162) --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 516426558d..84bc6a8056 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1441,7 +1441,7 @@ public class VcnGatewayConnection extends StateMachine { caps, lp, Vcn.getNetworkScore(), - new NetworkAgentConfig(), + new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override public void unwanted() { From b77348a3ebcd51a0c8b1f5ee1f2eeb5e7365a671 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 15:12:37 +0800 Subject: [PATCH 0139/1057] Remove reference of NetworkAgent#unwanted() This is hidden, use onNetworkUnwanted instead. Test: TH Bug: 182963397 Merged-In: I4e80a75d25cfd9ffc07aa219fff5a2604eb307f2 Change-Id: I4e80a75d25cfd9ffc07aa219fff5a2604eb307f2 (cherry-picked from ag/13925163) --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 84bc6a8056..673618b607 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1444,7 +1444,7 @@ public class VcnGatewayConnection extends StateMachine { new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override - public void unwanted() { + public void onNetworkUnwanted() { Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } From dc666be0459ff7cd5b3cc2a6e6900e8b0af1b627 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 15:37:54 +0800 Subject: [PATCH 0140/1057] Remove hidden API usage of RouteInfo For callers who use hidden constructor of RouteInfo, replace them with public constructor. Test: TH Bug: 182963397 Merged-In: I18d2cceafad633a95bd909b7f693d45e8a861bc9 Change-Id: I18d2cceafad633a95bd909b7f693d45e8a861bc9 (cherry-picked from ag/13925164) --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 673618b607..9589505ef2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1796,8 +1796,10 @@ public class VcnGatewayConnection extends StateMachine { lp.addDnsServer(addr); } - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); - lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); lp.setMtu(gatewayConnectionConfig.getMaxMtu()); From 8df1b4341eb499689494b188b10085b59df27be4 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 19:11:18 +0800 Subject: [PATCH 0141/1057] Remove the usage of hidden API and simplify the design - ConnectivityManager will be a part of mainline module, so its hidden API cannot be called by external caller. - There is no need to listen onNetworkSuspended() and onNetworkResumed() because if the network is suspended, then NET_CAPABILITY_NOT_SUSPENDED will be removed and onCapabilitiesChanged() will be called and the network capabilities will be different from the previous one. And when the network is resumed, NET_CAPABILITY_NOT_SUSPENDED will be added back to the network capabilities. So the current design can be simplified. Bug: 182963397 Test: atest FrameworksVcnTests Change-Id: Ib8f8ea1c95503c946b8229670512af2db8be3165 --- .../server/vcn/UnderlyingNetworkTracker.java | 30 +------------------ .../vcn/UnderlyingNetworkTrackerTest.java | 16 +++++++--- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 8dcc547508..6ff8d6f8ba 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -290,25 +290,6 @@ public class UnderlyingNetworkTracker { maybeNotifyCallback(); } - private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to isSuspended"); - return; - } - - final NetworkCapabilities newCaps = - new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities()); - if (isSuspended) { - newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } else { - newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } - - handleCapabilitiesChanged(network, newCaps); - } - private void handlePropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { mVcnContext.ensureRunningOnLooperThread(); @@ -366,19 +347,10 @@ public class UnderlyingNetworkTracker { @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return; handleCapabilitiesChanged(network, networkCapabilities); } - @Override - public void onNetworkSuspended(@NonNull Network network) { - handleNetworkSuspended(network, true /* isSuspended */); - } - - @Override - public void onNetworkResumed(@NonNull Network network) { - handleNetworkSuspended(network, false /* isSuspended */); - } - @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1ef1a61f17..631c862d2b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -328,7 +328,7 @@ public class UnderlyingNetworkTrackerTest { public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); - cb.onNetworkSuspended(mNetwork); + cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( @@ -336,7 +336,11 @@ public class UnderlyingNetworkTrackerTest { SUSPENDED_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't + // change. + cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -344,7 +348,7 @@ public class UnderlyingNetworkTrackerTest { RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); - cb.onNetworkResumed(mNetwork); + cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( @@ -352,7 +356,11 @@ public class UnderlyingNetworkTrackerTest { INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't + // change. + cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test From 8cca8313e63b87cbca31f794ed7b4eede461251b Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 23 Feb 2021 08:47:39 -0800 Subject: [PATCH 0142/1057] TransportInfo: Add a generic redaction mechanism This replaces the existing mechanism for redacting location sensitive fields with a more extensible mechanism. Currently supported redactions are for the following permissions: i. ACCESS_FINE_LOCATION ii. LOCAL_MAC_ADDRESS iii. NETWORK_SETTINGS Also, removed WifiInfo from ConnectivityServiceTest to reduce cross dependencies on wifi code. Bug: 156867433 Bug: 162602799 Test: atest android.net Test: atest com.android.server Change-Id: I2bb980c624667a55c1383f13ab71b9b97ed6eeab --- .../java/com/android/server/VcnManagementServiceTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 814cad4ab4..a9d5822be2 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -32,9 +32,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -656,7 +655,7 @@ public class VcnManagementServiceTest { .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); } else if (transport == TRANSPORT_WIFI) { WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); + when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo); when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); ncBuilder From 09cbd00362ea136a8390cc5c41a126f6bc87b90c Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Sun, 21 Mar 2021 17:55:29 +0000 Subject: [PATCH 0143/1057] resolve merge conflicts of 403b7fd0b0a6736bcee1817fb5c774f8c8a040de to stage-aosp-master Change-Id: Ib9d7923104ac0a60f6af5a3a2d2b7f13bc0262e3 --- .../java/com/android/server/VcnManagementServiceTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 814cad4ab4..a9d5822be2 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -32,9 +32,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -656,7 +655,7 @@ public class VcnManagementServiceTest { .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); } else if (transport == TRANSPORT_WIFI) { WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); + when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo); when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); ncBuilder From 9d65b751151005401d855d6812fe993fddd06107 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 11 Mar 2021 15:11:19 -0800 Subject: [PATCH 0144/1057] Rename VcnStatusCallback#onVcnStatusChanged. Per API Council feedback, VcnStatusCallback#onVcnStatusChanged is renamed to VcnStatusCallback#onStatusChanged. Bug: 182345902 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Ie0277c5f053e1802aa98240618a9d9e8aa6d9d09 --- Vcn/framework-b/src/android/net/vcn/VcnManager.java | 6 +++--- Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index b73fdbff8e..c0189e2202 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -439,7 +439,7 @@ public class VcnManager { * @param statusCode the code for the status change encountered by this {@link * VcnStatusCallback}'s subscription group. */ - public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); + public abstract void onStatusChanged(@VcnStatusCode int statusCode); /** * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group @@ -476,7 +476,7 @@ public class VcnManager { * and there is a VCN active for its specified subscription group (this may happen after the * callback is registered). * - *

      {@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the + *

      {@link VcnStatusCallback#onStatusChanged(int)} will be invoked on registration with the * current status for the specified subscription group's VCN. If the registrant is not * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be * returned. @@ -580,7 +580,7 @@ public class VcnManager { @Override public void onVcnStatusChanged(@VcnStatusCode int statusCode) { Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); + () -> mExecutor.execute(() -> mCallback.onStatusChanged(statusCode))); } // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 7515971b83..516c206672 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -204,7 +204,7 @@ public class VcnManagerTest { new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback); cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); - verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE); cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, From cce7c4929b7c9d4dabb4cd12d50ebda0670983ce Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 9 Mar 2021 17:10:26 -0800 Subject: [PATCH 0145/1057] Reevaluate VcnGatewayConnections on receiving new configs. This CL updates Vcn.java to reevaluate its VcnGatewayConnections when it receives a new VcnConfig. This may result in VcnGatewayConnections being torn down (if their VcnGatewayConnectionConfig is not in the updated VcnConfig) or established (if a NetworkRequest matches a new VcnGatewayConnectionConfig). Bug: 181815405 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I7da60f60e972bd968e1ff4fe416fb9a1d3309a18 --- .../src/com/android/server/vcn/Vcn.java | 76 +++++++++++++++--- .../java/com/android/server/vcn/VcnTest.java | 79 +++++++++++++++++-- 2 files changed, 138 insertions(+), 17 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 3f74938005..89ed956b3a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -110,6 +111,24 @@ public class Vcn extends Handler { @NonNull private final VcnNetworkRequestListener mRequestListener; @NonNull private final VcnCallback mVcnCallback; + /** + * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. + * + *

      Due to potential for race conditions, VcnGatewayConnections MUST only be created and added + * to this map in {@link #handleNetworkRequested(NetworkRequest, int, int)}, when a VCN receives + * a NetworkRequest that matches a VcnGatewayConnectionConfig for this VCN's VcnConfig. + * + *

      A VcnGatewayConnection instance MUST NEVER overwrite an existing instance - otherwise + * there is potential for a orphaned VcnGatewayConnection instance that does not get properly + * shut down. + * + *

      Due to potential for race conditions, VcnGatewayConnections MUST only be removed from this + * map once they have finished tearing down, which is reported to this VCN via {@link + * VcnGatewayStatusCallback#onQuit()}. Once this is done, all NetworkRequests are retrieved from + * the NetworkProvider so that another VcnGatewayConnectionConfig can match the + * previously-matched request. + */ + // TODO(b/182533200): remove the invariant on VcnGatewayConnection lifecycles @NonNull private final Map mVcnGatewayConnections = new HashMap<>(); @@ -191,6 +210,19 @@ public class Vcn extends Handler { return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values())); } + /** Get current Configs and Gateways for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Map + getVcnGatewayConnectionConfigMap() { + return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections)); + } + + /** Set whether this Vcn is active for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setIsActive(boolean isActive) { + mIsActive.set(isActive); + } + private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { @@ -202,11 +234,6 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { - // Ignore if this Vcn is not active and we're not receiving new configs - if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) { - return; - } - switch (msg.what) { case MSG_EVENT_CONFIG_UPDATED: handleConfigUpdated((VcnConfig) msg.obj); @@ -237,9 +264,31 @@ public class Vcn extends Handler { mConfig = config; - // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s) + if (mIsActive.getAndSet(true)) { + // VCN is already active - teardown any GatewayConnections whose configs have been + // removed and get all current requests + for (final Entry entry : + mVcnGatewayConnections.entrySet()) { + final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); + final VcnGatewayConnection gatewayConnection = entry.getValue(); - if (!mIsActive.getAndSet(true)) { + // GatewayConnectionConfigs must match exactly (otherwise authentication or + // connection details may have changed). + if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { + if (gatewayConnection == null) { + Slog.wtf( + getLogTag(), + "Found gatewayConnectionConfig without GatewayConnection"); + } else { + gatewayConnection.teardownAsynchronously(); + } + } + } + + // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be + // satisfied start a new GatewayConnection) + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } else { // If this VCN was not previously active, it is exiting Safe Mode. Re-register the // request listener to get NetworkRequests again (and all cached requests). mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); @@ -259,13 +308,16 @@ public class Vcn extends Handler { private void handleEnterSafeMode() { handleTeardown(); - mVcnGatewayConnections.clear(); - mVcnCallback.onEnteredSafeMode(); } private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { + if (!isActive()) { + Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now"); + return; + } + if (score > getNetworkScore()) { if (VDBG) { Slog.v( @@ -318,8 +370,10 @@ public class Vcn extends Handler { mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied - // start a new GatewayConnection) - mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + // start a new GatewayConnection), but only if the Vcn is still active + if (isActive()) { + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } } private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 4fa63d4ff6..c853fc50fd 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -29,6 +29,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -139,8 +140,7 @@ public class VcnTest { mTestLooper.dispatchAll(); } - @Test - public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { + private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); @@ -150,14 +150,27 @@ public class VcnTest { final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); + mVcn.setIsActive(isActive); + mVcn.updateSubscriptionSnapshot(updatedSnapshot); mTestLooper.dispatchAll(); for (final VcnGatewayConnection gateway : gatewayConnections) { - verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot)); + verify(gateway, isActive ? times(1) : never()) + .updateSubscriptionSnapshot(eq(updatedSnapshot)); } } + @Test + public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { + verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */); + } + + @Test + public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() { + verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -187,7 +200,6 @@ public class VcnTest { NetworkRequestListener requestListener, Set expectedGatewaysTornDown) { assertFalse(mVcn.isActive()); - assertTrue(mVcn.getVcnGatewayConnections().isEmpty()); for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { verify(gatewayConnection).teardownAsynchronously(); } @@ -237,6 +249,51 @@ public class VcnTest { mGatewayStatusCallbackCaptor.capture()); } + @Test + public void testGatewayQuitWhileInactive() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + mVcn.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onQuit(); + mTestLooper.dispatchAll(); + + // Verify that the VCN requests the networkRequests be resent + assertEquals(1, mVcn.getVcnGatewayConnections().size()); + verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener); + } + + @Test + public void testUpdateConfigReevaluatesGatewayConnections() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + startGatewaysAndGetGatewayConnections(requestListener); + assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size()); + + // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn + // down + final VcnGatewayConnectionConfig activeConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]); + final VcnGatewayConnectionConfig removedConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]); + final VcnConfig updatedConfig = + new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build(); + + mVcn.updateConfig(updatedConfig); + mTestLooper.dispatchAll(); + + final VcnGatewayConnection activeGatewayConnection = + mVcn.getVcnGatewayConnectionConfigMap().get(activeConfig); + final VcnGatewayConnection removedGatewayConnection = + mVcn.getVcnGatewayConnectionConfigMap().get(removedConfig); + verify(activeGatewayConnection, never()).teardownAsynchronously(); + verify(removedGatewayConnection).teardownAsynchronously(); + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + } + @Test public void testUpdateConfigExitsSafeMode() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); @@ -261,8 +318,8 @@ public class VcnTest { verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); assertTrue(mVcn.isActive()); for (final int[] caps : TEST_CAPS) { - // Expect each gateway connection created on initial startup, and again with new configs - verify(mDeps, times(2)) + // Expect each gateway connection created only on initial startup + verify(mDeps) .newVcnGatewayConnection( eq(mVcnContext), eq(TEST_SUB_GROUP), @@ -271,4 +328,14 @@ public class VcnTest { any()); } } + + @Test + public void testIgnoreNetworkRequestWhileInactive() { + mVcn.setIsActive(false /* isActive */); + + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + triggerVcnRequestListeners(requestListener); + + verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any()); + } } From 18982cce1959d2956ee03239df8c1ff8fb8d1a7e Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 22 Mar 2021 15:14:14 -0700 Subject: [PATCH 0146/1057] Cache correct calling UID for VcnStatusCallbacks. This CL updates VcnManagementService to cache the correct UID for the caller when a VcnStatusCallback is registered. Previously, getBinderCallingUid() was checked after the calling identity was cleared. Bug: 183437200 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Idfa2d2aad6bc03b3d08a137f9913276057632a3b --- Vcn/service-b/src/com/android/server/VcnManagementService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 6c18cdea51..d561ab96c3 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -821,8 +821,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IBinder cbBinder = callback.asBinder(); final VcnStatusCallbackInfo cbInfo = - new VcnStatusCallbackInfo( - subGroup, callback, opPkgName, mDeps.getBinderCallingUid()); + new VcnStatusCallbackInfo(subGroup, callback, opPkgName, callingUid); try { cbBinder.linkToDeath(cbInfo, 0 /* flags */); From 0308687500c01dd07ebe5f36da55d8787ab7017c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 22 Mar 2021 19:44:17 -0700 Subject: [PATCH 0147/1057] Check carrier privilege permissions with package name This change ensures that carrier privileges for the right packages are always checked. Bug: 183465199 Test: atest FrameworksVcnTests Change-Id: If46c660e54870529868a7b4b1e271c9009b81d45 --- .../net/vcn/IVcnManagementService.aidl | 2 +- .../src/android/net/vcn/VcnManager.java | 2 +- .../android/server/VcnManagementService.java | 19 ++++++---- .../server/VcnManagementServiceTest.java | 36 +++++++++++++------ 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 6a3cb42ed7..5b79f7311b 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -29,7 +29,7 @@ import android.os.ParcelUuid; */ interface IVcnManagementService { void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); - void clearVcnConfig(in ParcelUuid subscriptionGroup); + void clearVcnConfig(in ParcelUuid subscriptionGroup, in String opPkgName); void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index c0189e2202..abd41dacde 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -154,7 +154,7 @@ public class VcnManager { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); try { - mService.clearVcnConfig(subscriptionGroup); + mService.clearVcnConfig(subscriptionGroup, mContext.getOpPackageName()); } catch (ServiceSpecificException e) { throw new IOException(e); } catch (RemoteException e) { diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index d561ab96c3..642fc6bad5 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -349,7 +349,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } - private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) { + private void enforceCallingUserAndCarrierPrivilege( + ParcelUuid subscriptionGroup, String pkgName) { // Only apps running in the primary (system) user are allowed to configure the VCN. This is // in line with Telephony's behavior with regards to binding to a Carrier App provided // CarrierConfigService. @@ -363,12 +364,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup)); }); - final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class); for (SubscriptionInfo info : subscriptionInfos) { + final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class) + .createForSubscriptionId(info.getSubscriptionId()); + // Check subscription is active first; much cheaper/faster check, and an app (currently) // cannot be carrier privileged for inactive subscriptions. if (subMgr.isValidSlotIndex(info.getSimSlotIndex()) - && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) { + && telMgr.checkCarrierPrivilegesForPackage(pkgName) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { // TODO (b/173717728): Allow configuration for inactive, but manageable // subscriptions. // TODO (b/173718661): Check for whole subscription groups at a time. @@ -536,7 +540,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { @@ -554,11 +558,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { *

      Implements the IVcnManagementService Binder interface. */ @Override - public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { + public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + requireNonNull(opPkgName, "opPkgName was null"); Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + mContext.getSystemService(AppOpsManager.class) + .checkPackage(mDeps.getBinderCallingUid(), opPkgName); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index a9d5822be2..babea364ed 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -19,6 +19,8 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; +import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -238,9 +240,14 @@ public class VcnManagementServiceTest { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) .getSubscriptionsInGroup(any()); - doReturn(isPrivileged) + doReturn(mTelMgr) .when(mTelMgr) - .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); + .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); + doReturn(isPrivileged + ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) + .when(mTelMgr) + .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME)); } @Test @@ -391,7 +398,7 @@ public class VcnManagementServiceTest { mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); // Verify that new instance was different, and the old one was torn down @@ -492,7 +499,7 @@ public class VcnManagementServiceTest { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected IllegalStateException exception for system server"); } catch (IllegalStateException expected) { } @@ -505,7 +512,7 @@ public class VcnManagementServiceTest { .getBinderCallingUid(); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected security exception for non system user"); } catch (SecurityException expected) { } @@ -516,15 +523,24 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } } + @Test + public void testClearVcnConfigMismatchedPackages() throws Exception { + try { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage"); + fail("Expected security exception due to mismatched packages"); + } catch (SecurityException expected) { + } + } + @Test public void testClearVcnConfig() throws Exception { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } @@ -535,7 +551,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); } @@ -564,7 +580,7 @@ public class VcnManagementServiceTest { verify(vcnInstance).updateConfig(TEST_VCN_CONFIG); // Verify Vcn is stopped if it was already started - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(vcnInstance).teardownAsynchronously(); } @@ -781,7 +797,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(mMockPolicyListener).onPolicyChanged(); } From ee62cb4d6641b43876d63bff4b45d66c0d3a8478 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 22 Mar 2021 20:07:58 -0700 Subject: [PATCH 0148/1057] Trigger re-evaluation of privileged apps upon app install/uninstall This change registers listeners for package installs and uninstalls, ensuring that changes to app install statuses are reflected in the VCN Bug: 183465258 Test: atest FrameworksVcnTests Change-Id: I8d2afd351208cac12392bf945439845cc521b7ec --- .../android/server/VcnManagementService.java | 27 +++++++++++ .../server/VcnManagementServiceTest.java | 45 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 642fc6bad5..4622e98bbb 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -29,7 +29,10 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -158,6 +161,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; @NonNull private final VcnContext mVcnContext; + @NonNull private final BroadcastReceiver mPkgChangeReceiver; /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */ @Nullable private LocationPermissionChecker mLocationPermissionChecker; @@ -203,6 +207,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider); + mPkgChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (Intent.ACTION_PACKAGE_ADDED.equals(action) + || Intent.ACTION_PACKAGE_REPLACED.equals(action) + || Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + mTelephonySubscriptionTracker.handleSubscriptionsChanged(); + } else { + Log.wtf(TAG, "received unexpected intent: " + action); + } + } + }; + + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + mContext.registerReceiver( + mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler); + // Run on handler to ensure I/O does not block system server startup mHandler.post(() -> { PersistableBundle configBundle = null; diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index babea364ed..f15d4204d1 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -49,7 +49,9 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.AppOpsManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -336,6 +338,13 @@ public class VcnManagementServiceTest { return captor.getValue(); } + private BroadcastReceiver getPackageChangeReceiver() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any()); + return captor.getValue(); + } + private Vcn startAndGetVcnInstance(ParcelUuid uuid) { mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); return mVcnMgmtSvc.getAllVcns().get(uuid); @@ -411,6 +420,42 @@ public class VcnManagementServiceTest { verify(newInstance, never()).teardownAsynchronously(); } + @Test + public void testPackageChangeListenerRegistered() throws Exception { + verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + } + + @Test + public void testPackageChangeListener_packageAdded() throws Exception { + final BroadcastReceiver receiver = getPackageChangeReceiver(); + + verify(mMockContext).registerReceiver(any(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + + receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED)); + verify(mSubscriptionTracker).handleSubscriptionsChanged(); + } + + @Test + public void testPackageChangeListener_packageRemoved() throws Exception { + final BroadcastReceiver receiver = getPackageChangeReceiver(); + + verify(mMockContext).registerReceiver(any(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + + receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED)); + verify(mSubscriptionTracker).handleSubscriptionsChanged(); + } + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); From 0d0bfdf8948cf103b519ec9a6135ac0cc59c2bcd Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 24 Mar 2021 16:22:18 -0700 Subject: [PATCH 0149/1057] Use 'gatewayConnectionName' for VcnGatewayConnection IDs. This CL updates VCN CTS testing to specify a gatewayConnectionName for configured VcnGatewayConnectionConfigs, per API Council feedback. Bug: 182345902 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I00382184aa10b97b22e733b25cb42ccd1d7ab8d8 --- .../src/android/net/vcn/cts/VcnManagerTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 71d68358a1..107ae44134 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -69,6 +69,8 @@ public class VcnManagerTest { private static final Executor INLINE_EXECUTOR = Runnable::run; + private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; @@ -125,7 +127,7 @@ public class VcnManagerTest { new VcnControlPlaneIkeConfig(ikeParams, childParams); final VcnGatewayConnectionConfig gatewayConnConfig = - new VcnGatewayConnectionConfig.Builder(controlConfig) + new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, controlConfig) .addExposedCapability(NET_CAPABILITY_INTERNET) .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) .setRetryInterval( @@ -244,9 +246,9 @@ public class VcnManagerTest { @Override public void onGatewayConnectionError( - @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) { + @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) { mFutureOnGatewayConnectionError.complete( - new GatewayConnectionError(networkCapabilities, errorCode, detail)); + new GatewayConnectionError(gatewayConnectionName, errorCode, detail)); } public int awaitOnStatusChanged() throws Exception { @@ -260,13 +262,13 @@ public class VcnManagerTest { /** Info class for organizing VcnStatusCallback#onGatewayConnectionError response data. */ private static class GatewayConnectionError { - @NonNull public final int[] networkCapabilities; + @NonNull public final String gatewayConnectionName; public final int errorCode; @Nullable public final Throwable detail; public GatewayConnectionError( - @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) { - this.networkCapabilities = networkCapabilities.clone(); + @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) { + this.gatewayConnectionName = gatewayConnectionName; this.errorCode = errorCode; this.detail = detail; } From 7ed307f30fe6d3f646dd8fc445d5c5cf9835cf69 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 19:11:18 +0800 Subject: [PATCH 0150/1057] Remove the usage of hidden API and simplify the design - ConnectivityManager will be a part of mainline module, so its hidden API cannot be called by external caller. - There is no need to listen onNetworkSuspended() and onNetworkResumed() because if the network is suspended, then NET_CAPABILITY_NOT_SUSPENDED will be removed and onCapabilitiesChanged() will be called and the network capabilities will be different from the previous one. And when the network is resumed, NET_CAPABILITY_NOT_SUSPENDED will be added back to the network capabilities. So the current design can be simplified. Bug: 182963397 Test: atest FrameworksVcnTests Change-Id: Ib8f8ea1c95503c946b8229670512af2db8be3165 Merged-In: Ib8f8ea1c95503c946b8229670512af2db8be3165 (cherry-picked from ag/13927656) --- .../server/vcn/UnderlyingNetworkTracker.java | 30 +------------------ .../vcn/UnderlyingNetworkTrackerTest.java | 16 +++++++--- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 8dcc547508..6ff8d6f8ba 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -290,25 +290,6 @@ public class UnderlyingNetworkTracker { maybeNotifyCallback(); } - private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to isSuspended"); - return; - } - - final NetworkCapabilities newCaps = - new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities()); - if (isSuspended) { - newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } else { - newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } - - handleCapabilitiesChanged(network, newCaps); - } - private void handlePropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { mVcnContext.ensureRunningOnLooperThread(); @@ -366,19 +347,10 @@ public class UnderlyingNetworkTracker { @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return; handleCapabilitiesChanged(network, networkCapabilities); } - @Override - public void onNetworkSuspended(@NonNull Network network) { - handleNetworkSuspended(network, true /* isSuspended */); - } - - @Override - public void onNetworkResumed(@NonNull Network network) { - handleNetworkSuspended(network, false /* isSuspended */); - } - @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1ef1a61f17..631c862d2b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -328,7 +328,7 @@ public class UnderlyingNetworkTrackerTest { public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); - cb.onNetworkSuspended(mNetwork); + cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( @@ -336,7 +336,11 @@ public class UnderlyingNetworkTrackerTest { SUSPENDED_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't + // change. + cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -344,7 +348,7 @@ public class UnderlyingNetworkTrackerTest { RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); - cb.onNetworkResumed(mNetwork); + cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( @@ -352,7 +356,11 @@ public class UnderlyingNetworkTrackerTest { INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't + // change. + cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test From feb79cec14c2af52b79b084b4dee0c5e25bfe99a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 19 Mar 2021 00:18:29 -0700 Subject: [PATCH 0151/1057] Switch to using list-of-subIds for VCN selection of underlying networks This change switches from primarily using unwanted(NOT_VCN_MANAGED) to list-of-subIds. This opens the door for a soft-start, predicated on the VCN-exposed networks not populating their respective subId fields. Allowing the potential for soft-start means that the VCN can exit safe mode without carrier app intervention, when all requested configurations are active. Bug: 183174340 Test: atest FrameworksVcnTests Change-Id: I57ecf4f5f04dc5d15589b17d647661674595b872 --- .../server/vcn/UnderlyingNetworkTracker.java | 158 +++++++----------- .../vcn/UnderlyingNetworkTrackerTest.java | 66 ++++---- 2 files changed, 92 insertions(+), 132 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 8dcc547508..a174807ac6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -27,15 +27,14 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.os.ParcelUuid; -import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -59,9 +58,9 @@ public class UnderlyingNetworkTracker { @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; - @NonNull private final Map mCellBringupCallbacks = new ArrayMap<>(); - @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback(); - @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); + @NonNull private final List mCellBringupCallbacks = new ArrayList<>(); + @Nullable private NetworkCallback mWifiBringupCallback; + @Nullable private NetworkCallback mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; private boolean mIsQuitting = false; @@ -105,36 +104,59 @@ public class UnderlyingNetworkTracker { mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); - registerNetworkRequests(); + registerOrUpdateNetworkRequests(); } - private void registerNetworkRequests() { - // register bringup requests for underlying Networks - mConnectivityManager.requestBackgroundNetwork( - getWifiNetworkRequest(), mHandler, mWifiBringupCallback); - updateSubIdsAndCellularRequests(); + private void registerOrUpdateNetworkRequests() { + NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; + NetworkCallback oldWifiCallback = mWifiBringupCallback; + List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); + mCellBringupCallbacks.clear(); - // Register Network-selection request used to decide selected underlying Network. All - // underlying networks must be VCN managed in order to be used. - mConnectivityManager.requestBackgroundNetwork( - getBaseNetworkRequest(true /* requireVcnManaged */).build(), - mHandler, - mRouteSelectionCallback); + // Register new callbacks. Make-before-break; always register new callbacks before removal + // of old callbacks + if (!mIsQuitting) { + mRouteSelectionCallback = new RouteSelectionCallback(); + mConnectivityManager.requestBackgroundNetwork( + getBaseNetworkRequestBuilder().build(), mHandler, mRouteSelectionCallback); + + mWifiBringupCallback = new NetworkBringupCallback(); + mConnectivityManager.requestBackgroundNetwork( + getWifiNetworkRequest(), mHandler, mWifiBringupCallback); + + for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + final NetworkBringupCallback cb = new NetworkBringupCallback(); + mCellBringupCallbacks.add(cb); + + mConnectivityManager.requestBackgroundNetwork( + getCellNetworkRequestForSubId(subId), mHandler, cb); + } + } else { + mRouteSelectionCallback = null; + mWifiBringupCallback = null; + // mCellBringupCallbacks already cleared above. + } + + // Unregister old callbacks (as necessary) + if (oldRouteSelectionCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldRouteSelectionCallback); + } + if (oldWifiCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiCallback); + } + for (NetworkCallback cellBringupCallback : oldCellCallbacks) { + mConnectivityManager.unregisterNetworkCallback(cellBringupCallback); + } } private NetworkRequest getWifiNetworkRequest() { - // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi - // alive. - return getBaseNetworkRequest(true /* requireVcnManaged */) + return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } private NetworkRequest getCellNetworkRequestForSubId(int subId) { - // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a - // fulfillable request to bring up underlying cellular Networks even if the VCN is already - // connected. - return getBaseNetworkRequest(false /* requireVcnManaged */) + return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); @@ -143,67 +165,19 @@ public class UnderlyingNetworkTracker { /** * Builds and returns a NetworkRequest builder common to all Underlying Network requests * - *

      A NetworkRequest may either (1) Require the presence of a capability by using - * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3) - * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED - * capability, and only cases (2) and (3) are used. - * - * @param requireVcnManaged whether the underlying network is required to be VCN managed to - * match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as - * unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is - * acceptable. + *

      This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue + * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier + * owned networks may be selected, as the request specifies only subIds in the VCN's + * subscription group, while the VCN networks are excluded by virtue of not having subIds set on + * the VCN-exposed networks. */ - private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) { - NetworkRequest.Builder requestBase = - new NetworkRequest.Builder() - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - - for (int capability : mRequiredUnderlyingNetworkCapabilities) { - requestBase.addCapability(capability); - } - - if (requireVcnManaged) { - requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } - - return requestBase; - } - - /** - * Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker. - */ - private void updateSubIdsAndCellularRequests() { - mVcnContext.ensureRunningOnLooperThread(); - - // Don't bother re-filing NetworkRequests if this Tracker has been torn down. - if (mIsQuitting) { - return; - } - - final Set subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); - - // new subIds to track = (updated list of subIds) - (currently tracked subIds) - final Set subIdsToRegister = new ArraySet<>(subIdsInSubGroup); - subIdsToRegister.removeAll(mCellBringupCallbacks.keySet()); - - // subIds to stop tracking = (currently tracked subIds) - (updated list of subIds) - final Set subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet()); - subIdsToUnregister.removeAll(subIdsInSubGroup); - - for (final int subId : subIdsToRegister) { - final NetworkBringupCallback cb = new NetworkBringupCallback(); - mCellBringupCallbacks.put(subId, cb); - - mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), mHandler, cb); - } - - for (final int subId : subIdsToUnregister) { - final NetworkCallback cb = mCellBringupCallbacks.remove(subId); - mConnectivityManager.unregisterNetworkCallback(cb); - } + private NetworkRequest.Builder getBaseNetworkRequestBuilder() { + return new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); } /** @@ -217,22 +191,16 @@ public class UnderlyingNetworkTracker { Objects.requireNonNull(snapshot, "Missing snapshot"); mLastSnapshot = snapshot; - updateSubIdsAndCellularRequests(); + registerOrUpdateNetworkRequests(); } /** Tears down this Tracker, and releases all underlying network requests. */ public void teardown() { mVcnContext.ensureRunningOnLooperThread(); - - mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback); - mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback); - - for (final NetworkCallback cb : mCellBringupCallbacks.values()) { - mConnectivityManager.unregisterNetworkCallback(cb); - } - mCellBringupCallbacks.clear(); - mIsQuitting = true; + + // Will unregister all existing callbacks, but not register new ones due to quitting flag. + registerOrUpdateNetworkRequests(); } /** Returns whether the currently selected Network matches the given network. */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1ef1a61f17..b33431ab5b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -146,40 +146,34 @@ public class UnderlyingNetworkTrackerTest { @Test public void testNetworkCallbacksRegisteredOnStartup() { - // verify NetworkCallbacks registered when instantiated - verify(mConnectivityManager) - .requestBackgroundNetwork( - eq(getWifiRequest()), - any(), - any(NetworkBringupCallback.class)); - verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); - - verify(mConnectivityManager) - .requestBackgroundNetwork( - eq(getRouteSelectionRequest()), - any(), - any(RouteSelectionCallback.class)); + verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); } - private void verifyBackgroundCellRequests( - TelephonySubscriptionSnapshot snapshot, - ParcelUuid subGroup, - Set expectedSubIds) { - verify(snapshot).getAllSubIdsInGroup(eq(subGroup)); - + private void verifyNetworkRequestsRegistered(Set expectedSubIds) { + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getWifiRequest(expectedSubIds)), + any(), + any(NetworkBringupCallback.class)); for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getCellRequestForSubId(subId)), + eq(getCellRequestForSubId(subId, expectedSubIds)), any(), any(NetworkBringupCallback.class)); } + + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getRouteSelectionRequest(expectedSubIds)), + any(), + any(RouteSelectionCallback.class)); } @Test public void testUpdateSubscriptionSnapshot() { // Verify initial cell background requests filed - verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); + verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); TelephonySubscriptionSnapshot subscriptionUpdate = mock(TelephonySubscriptionSnapshot.class); @@ -187,40 +181,38 @@ public class UnderlyingNetworkTrackerTest { mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); - // verify that initially-filed bringup requests are unregistered - verify(mConnectivityManager, times(INITIAL_SUB_IDS.size())) + // verify that initially-filed bringup requests are unregistered (cell + wifi) + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS); + verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); } - private NetworkRequest getWifiRequest() { - return getExpectedRequestBase(true) + private NetworkRequest getWifiRequest(Set netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } - private NetworkRequest getCellRequestForSubId(int subId) { - return getExpectedRequestBase(false) + private NetworkRequest getCellRequestForSubId(int subId, Set netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } - private NetworkRequest getRouteSelectionRequest() { - return getExpectedRequestBase(true).build(); + private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds).build(); } - private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) { + private NetworkRequest.Builder getExpectedRequestBase(Set subIds) { final NetworkRequest.Builder builder = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - - if (requireVcnManaged) { - builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setSubIds(subIds); return builder; } @@ -274,7 +266,7 @@ public class UnderlyingNetworkTrackerTest { NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getRouteSelectionRequest()), + eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), any(), mRouteSelectionCallbackCaptor.capture()); From e654107895a8f53a6b8f6ce26996c4cc4011d8ca Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 19 Mar 2021 00:25:53 -0700 Subject: [PATCH 0152/1057] Switch to using list of subIds for policy generation Bug: 183174340 Test: atest FrameworksVcnTests Change-Id: I2d30b75c282cf619d81b0f6dc06638566af61a33 --- .../android/server/VcnManagementService.java | 57 ++++++++++--------- .../server/VcnManagementServiceTest.java | 26 +++------ 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 4622e98bbb..8eefbfc606 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -36,7 +36,6 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; -import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -717,19 +716,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } - private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) - && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); - return telephonyNetworkSpecifier.getSubscriptionId(); - } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) - && networkCapabilities.getTransportInfo() instanceof WifiInfo) { - WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - return mDeps.getSubIdForWifiInfo(wifiInfo); + private ParcelUuid getSubGroupForNetworkCapabilities( + @NonNull NetworkCapabilities networkCapabilities) { + ParcelUuid subGrp = null; + final TelephonySubscriptionSnapshot snapshot; + + // Always access mLastSnapshot under lock. Technically this can be treated as a volatile + // but for consistency and safety, always access under lock. + synchronized (mLock) { + snapshot = mLastSnapshot; } - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + // If multiple subscription IDs exist, they MUST all point to the same subscription + // group. Otherwise undefined behavior may occur. + for (int subId : networkCapabilities.getSubIds()) { + // Verify that all subscriptions point to the same group + if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { + Slog.wtf(TAG, "Got multiple subscription groups for a single network"); + } + + subGrp = snapshot.getGroupForSubId(subId); + } + + return subGrp; } /** @@ -754,23 +763,19 @@ public class VcnManagementService extends IVcnManagementService.Stub { // mutates final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities); - final int subId = getSubIdForNetworkCapabilities(ncCopy); + final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy); boolean isVcnManagedNetwork = false; boolean isRestrictedCarrierWifi = false; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - synchronized (mLock) { - ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); + synchronized (mLock) { + final Vcn vcn = mVcns.get(subGrp); + if (vcn != null) { + if (vcn.isActive()) { + isVcnManagedNetwork = true; + } - final Vcn vcn = mVcns.get(subGroup); - if (vcn != null) { - if (vcn.isActive()) { - isVcnManagedNetwork = true; - } - - if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - // Carrier WiFi always restricted if VCN exists (even in safe mode). - isRestrictedCarrierWifi = true; - } + if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + // Carrier WiFi always restricted if VCN exists (even in safe mode). + isRestrictedCarrierWifi = true; } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index f15d4204d1..c88b0c1547 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -34,8 +34,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -45,7 +45,6 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; 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.AppOpsManager; @@ -63,7 +62,6 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; -import android.net.wifi.WifiInfo; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -708,22 +706,12 @@ public class VcnManagementServiceTest { int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) { setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); - final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(); - ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - if (transport == TRANSPORT_CELLULAR) { - ncBuilder - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); - } else if (transport == TRANSPORT_WIFI) { - WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo); - when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); - - ncBuilder - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setTransportInfo(wifiInfo); - } else { - throw new IllegalArgumentException("Unknown transport"); + final NetworkCapabilities.Builder ncBuilder = + new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .addTransportType(transport); + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + ncBuilder.setSubIds(Collections.singleton(subId)); } return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties()); From fb76bdb5cef4b0bde3e905fdbbcca4fbd56ac62d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 12 Mar 2021 18:29:19 -0800 Subject: [PATCH 0153/1057] Update identification for onGatewayConnectionError(). This CL updates the identification method for VcnStatusCallback#onGatewayConnectionErrror. Previously, GatewayConnections were identified by an int[] specifying the GatewayConnection's exposed NetworkCapabilities. Following API Council feedback, this is updated to identify GatewayConnections by a caller-provided String set in the VcnGatewayConnectionConfig.Builder. Bug: 182345902 Bug: 180522464 Test: atest FrameworksVcnTests Change-Id: I933c2330edb9bfc1b6bb62276debac02460e24f8 --- .../android/net/vcn/IVcnStatusCallback.aidl | 2 +- .../src/android/net/vcn/VcnConfig.java | 13 +++++ .../net/vcn/VcnGatewayConnectionConfig.java | 49 ++++++++++++++++++- .../src/android/net/vcn/VcnManager.java | 4 +- .../android/server/VcnManagementService.java | 6 +-- .../src/com/android/server/vcn/Vcn.java | 6 +-- .../server/vcn/VcnGatewayConnection.java | 4 +- .../java/android/net/vcn/VcnConfigTest.java | 12 +++++ .../vcn/VcnGatewayConnectionConfigTest.java | 28 ++++++++++- .../java/android/net/vcn/VcnManagerTest.java | 8 ++- ...cnGatewayConnectionConnectedStateTest.java | 7 ++- .../java/com/android/server/vcn/VcnTest.java | 13 +++-- 12 files changed, 126 insertions(+), 26 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl index 236ae8bb11..11bc443c9d 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnStatusCallback.aidl @@ -20,7 +20,7 @@ package android.net.vcn; oneway interface IVcnStatusCallback { void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( - in int[] gatewayNetworkCapabilities, + in String gatewayConnectionName, int errorCode, in String exceptionClass, in String exceptionMessage); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index 52cc2182b0..d41c0b4fbd 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -183,12 +183,25 @@ public final class VcnConfig implements Parcelable { * * @param gatewayConnectionConfig the configuration for an individual gateway connection * @return this {@link Builder} instance, for chaining + * @throws IllegalArgumentException if a VcnGatewayConnectionConfig has already been set for + * this {@link VcnConfig} with the same GatewayConnection name (as returned via {@link + * VcnGatewayConnectionConfig#getGatewayConnectionName()}). */ @NonNull public Builder addGatewayConnectionConfig( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null"); + for (final VcnGatewayConnectionConfig vcnGatewayConnectionConfig : + mGatewayConnectionConfigs) { + if (vcnGatewayConnectionConfig + .getGatewayConnectionName() + .equals(gatewayConnectionConfig.getGatewayConnectionName())) { + throw new IllegalArgumentException( + "GatewayConnection for specified name already exists"); + } + } + mGatewayConnectionConfigs.add(gatewayConnectionConfig); return this; } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index d4e8e2dca2..ae52cc45a9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -148,6 +148,8 @@ public final class VcnGatewayConnectionConfig { TimeUnit.MINUTES.toMillis(5), TimeUnit.MINUTES.toMillis(15) }; + private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName"; + @NonNull private final String mGatewayConnectionName; private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig"; @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig; @@ -166,11 +168,13 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( + @NonNull String gatewayConnectionName, @NonNull VcnControlPlaneConfig ctrlPlaneConfig, @NonNull Set exposedCapabilities, @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { + mGatewayConnectionName = gatewayConnectionName; mCtrlPlaneConfig = ctrlPlaneConfig; mExposedCapabilities = new TreeSet(exposedCapabilities); mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); @@ -192,6 +196,7 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle underlyingCapsBundle = in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); + mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); @@ -204,6 +209,7 @@ public final class VcnGatewayConnectionConfig { } private void validate() { + Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null"); Preconditions.checkArgument( @@ -241,6 +247,21 @@ public final class VcnGatewayConnectionConfig { } } + /** + * Returns the configured Gateway Connection name. + * + *

      This name is used by the configuring apps to distinguish between + * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as + * the identifier in VcnStatusCallback invocations. + * + * @see VcnManager.VcnStatusCallback#onGatewayConnectionError + * @hide + */ + @NonNull + public String getGatewayConnectionName() { + return mGatewayConnectionName; + } + /** * Returns control plane configuration. * @@ -364,6 +385,7 @@ public final class VcnGatewayConnectionConfig { new ArrayList<>(mUnderlyingCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); + result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); @@ -376,6 +398,7 @@ public final class VcnGatewayConnectionConfig { @Override public int hashCode() { return Objects.hash( + mGatewayConnectionName, mExposedCapabilities, mUnderlyingCapabilities, Arrays.hashCode(mRetryIntervalsMs), @@ -389,7 +412,8 @@ public final class VcnGatewayConnectionConfig { } final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; - return mExposedCapabilities.equals(rhs.mExposedCapabilities) + return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) + && mExposedCapabilities.equals(rhs.mExposedCapabilities) && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; @@ -399,6 +423,7 @@ public final class VcnGatewayConnectionConfig { * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ public static final class Builder { + @NonNull private final String mGatewayConnectionName; @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig; @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @@ -416,8 +441,29 @@ public final class VcnGatewayConnectionConfig { * @see VcnControlPlaneConfig */ public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) { + this("" /* gatewayConnectionName */, ctrlPlaneConfig); + } + + /** + * Construct a Builder object. + * + * @param gatewayConnectionName the String GatewayConnection name for this + * VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link + * VcnConfig} must be given a unique name. This name is used by the caller to + * distinguish between VcnGatewayConnectionConfigs configured on a single {@link + * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. + * @param ctrlPlaneConfig the control plane configuration + * @see VcnControlPlaneConfig + * @see VcnManager.VcnStatusCallback#onGatewayConnectionError + * @hide + */ + public Builder( + @NonNull String gatewayConnectionName, + @NonNull VcnControlPlaneConfig ctrlPlaneConfig) { + Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null"); + mGatewayConnectionName = gatewayConnectionName; mCtrlPlaneConfig = ctrlPlaneConfig; } @@ -562,6 +608,7 @@ public final class VcnGatewayConnectionConfig { @NonNull public VcnGatewayConnectionConfig build() { return new VcnGatewayConnectionConfig( + mGatewayConnectionName, mCtrlPlaneConfig, mExposedCapabilities, mUnderlyingCapabilities, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index abd41dacde..36be16f577 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -586,7 +586,7 @@ public class VcnManager { // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' @Override public void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage) { @@ -597,7 +597,7 @@ public class VcnManager { mExecutor.execute( () -> mCallback.onGatewayConnectionError( - networkCapabilities, errorCode, cause))); + new int[0], errorCode, cause))); } private static Throwable createThrowableByClassName( diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 4622e98bbb..bb333c78d1 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -926,7 +926,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Called by a Vcn to signal that an error occurred. */ void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage); @@ -955,7 +955,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @Override public void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage) { @@ -971,7 +971,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { Binder.withCleanCallingIdentity( () -> cbInfo.mCallback.onGatewayConnectionError( - networkCapabilities, + gatewayConnectionName, errorCode, exceptionClass, exceptionMessage)); diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 89ed956b3a..c0130da7dd 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -417,7 +417,7 @@ public class Vcn extends Handler { /** Callback by a VcnGatewayConnection to indicate that an error occurred. */ void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage); @@ -445,12 +445,12 @@ public class Vcn extends Handler { @Override public void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage) { mVcnCallback.onGatewayConnectionError( - networkCapabilities, errorCode, exceptionClass, exceptionMessage); + gatewayConnectionName, errorCode, exceptionClass, exceptionMessage); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 9589505ef2..2ba8edd3b1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -980,7 +980,7 @@ public class VcnGatewayConnection extends StateMachine { // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed() if (exception != null) { mGatewayStatusCallback.onGatewayConnectionError( - mConnectionConfig.getExposedCapabilities(), + mConnectionConfig.getGatewayConnectionName(), VCN_ERROR_CODE_INTERNAL_ERROR, RuntimeException.class.getName(), "Received " @@ -1017,7 +1017,7 @@ public class VcnGatewayConnection extends StateMachine { } mGatewayStatusCallback.onGatewayConnectionError( - mConnectionConfig.getExposedCapabilities(), + mConnectionConfig.getGatewayConnectionName(), errorCode, exceptionClass, exceptionMessage); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java index c1ef350e5c..7ac51b7e33 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java @@ -78,6 +78,18 @@ public class VcnConfigTest { } } + @Test + public void testBuilderRequiresUniqueGatewayConnectionNames() { + final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.buildTestConfig(); + try { + new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig(config) + .addGatewayConnectionConfig(config); + fail("Expected exception due to duplicate gateway connection name"); + } catch (IllegalArgumentException e) { + } + } + @Test public void testBuilderAndGetters() { final VcnConfig config = buildTestConfig(mContext); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 8a0c923d5f..4ee4d611e9 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -19,6 +19,7 @@ package android.net.vcn; 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.NetworkCapabilities; @@ -61,13 +62,20 @@ public class VcnGatewayConnectionConfigTest { public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG = VcnControlPlaneIkeConfigTest.buildTestConfig(); + public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; + private static int sGatewayConnectionConfigCount = 0; + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { return buildTestConfigWithExposedCaps(EXPOSED_CAPS); } private static VcnGatewayConnectionConfig.Builder newBuilder() { - return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG); + // Append a unique identifier to the name prefix to guarantee that all created + // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig). + return new VcnGatewayConnectionConfig.Builder( + GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++, + CONTROL_PLANE_CONFIG); } // Public for use in VcnGatewayConnectionTest @@ -86,10 +94,24 @@ public class VcnGatewayConnectionConfigTest { return builder.build(); } + @Test + public void testBuilderRequiresNonNullGatewayConnectionName() { + try { + new VcnGatewayConnectionConfig.Builder( + null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG) + .build(); + + fail("Expected exception due to invalid gateway connection name"); + } catch (NullPointerException e) { + } + } + @Test public void testBuilderRequiresNonNullControlPlaneConfig() { try { - new VcnGatewayConnectionConfig.Builder(null).build(); + new VcnGatewayConnectionConfig.Builder( + GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */) + .build(); fail("Expected exception due to invalid control plane config"); } catch (NullPointerException e) { @@ -139,6 +161,8 @@ public class VcnGatewayConnectionConfigTest { public void testBuilderAndGetters() { final VcnGatewayConnectionConfig config = buildTestConfig(); + assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX)); + int[] exposedCaps = config.getExposedCapabilities(); Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 516c206672..54cdeb8be5 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -50,9 +50,7 @@ import java.util.concurrent.Executor; public class VcnManagerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); - private static final int[] UNDERLYING_NETWORK_CAPABILITIES = { - NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET - }; + private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName"; private static final Executor INLINE_EXECUTOR = Runnable::run; private IVcnManagementService mMockVcnManagementService; @@ -207,13 +205,13 @@ public class VcnManagerTest { verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE); cbBinder.onGatewayConnectionError( - UNDERLYING_NETWORK_CAPABILITIES, + GATEWAY_CONNECTION_NAME, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, UnknownHostException.class.getName(), "exception_message"); verify(mMockStatusCallback) .onGatewayConnectionError( - eq(UNDERLYING_NETWORK_CAPABILITIES), + any(int[].class), eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR), any(UnknownHostException.class)); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index ca6448ca9b..2fadd44440 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -241,7 +241,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mGatewayStatusCallback) .onGatewayConnectionError( - eq(mConfig.getExposedCapabilities()), + eq(mConfig.getGatewayConnectionName()), eq(VCN_ERROR_CODE_INTERNAL_ERROR), any(), any()); @@ -275,7 +275,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mGatewayStatusCallback) .onGatewayConnectionError( - eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any()); + eq(mConfig.getGatewayConnectionName()), + eq(expectedErrorType), + any(), + any()); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index c853fc50fd..530d8348bf 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -51,7 +51,9 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -274,11 +276,12 @@ public class VcnTest { assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size()); // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn - // down - final VcnGatewayConnectionConfig activeConfig = - VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]); - final VcnGatewayConnectionConfig removedConfig = - VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]); + // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name + // matches. + final List currentConfigs = + new ArrayList<>(mVcn.getVcnGatewayConnectionConfigMap().keySet()); + final VcnGatewayConnectionConfig activeConfig = currentConfigs.get(0); + final VcnGatewayConnectionConfig removedConfig = currentConfigs.get(1); final VcnConfig updatedConfig = new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build(); From 45765cfffae916ce20ff56388c59a0846623e629 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 30 Mar 2021 17:39:58 -0700 Subject: [PATCH 0154/1057] Expose API for identifying GatewayConnections. This CL exposes the updated APIs for identifying GatewayConnections via a user-configured String set in VcnGatewayConnectionConfig.Builder, as requested by the API Council. Bug: 182345902 Bug: 180522464 Test: atest FrameworksVcnTests Change-Id: I10afd074906bc0f3831157dcee1da813b4cfce78 --- .../net/vcn/VcnGatewayConnectionConfig.java | 12 ------------ .../src/android/net/vcn/VcnManager.java | 14 ++++++-------- .../unit/java/android/net/vcn/VcnManagerTest.java | 2 +- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index ae52cc45a9..75db3820f5 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -255,7 +255,6 @@ public final class VcnGatewayConnectionConfig { * the identifier in VcnStatusCallback invocations. * * @see VcnManager.VcnStatusCallback#onGatewayConnectionError - * @hide */ @NonNull public String getGatewayConnectionName() { @@ -434,16 +433,6 @@ public final class VcnGatewayConnectionConfig { // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS // when on Cell. - /** - * Construct a Builder object. - * - * @param ctrlPlaneConfig the control plane configuration - * @see VcnControlPlaneConfig - */ - public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) { - this("" /* gatewayConnectionName */, ctrlPlaneConfig); - } - /** * Construct a Builder object. * @@ -455,7 +444,6 @@ public final class VcnGatewayConnectionConfig { * @param ctrlPlaneConfig the control plane configuration * @see VcnControlPlaneConfig * @see VcnManager.VcnStatusCallback#onGatewayConnectionError - * @hide */ public Builder( @NonNull String gatewayConnectionName, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 36be16f577..d09094cee1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -445,18 +445,16 @@ public class VcnManager { * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group * encounters an error. * - * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities - * for the Gateway Connection that encountered the error, for identification purposes. - * These will be a sorted list with no duplicates and will match {@link - * VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link - * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription - * group. + * @param gatewayConnectionName the String GatewayConnection name for the GatewayConnection + * encountering an error. This will match the name for exactly one {@link + * VcnGatewayConnectionConfig} for the {@link VcnConfig} configured for this callback's + * subscription group * @param errorCode the code to indicate the error that occurred * @param detail Throwable to provide additional information about the error, or {@code * null} if none */ public abstract void onGatewayConnectionError( - @NonNull int[] networkCapabilities, + @NonNull String gatewayConnectionName, @VcnErrorCode int errorCode, @Nullable Throwable detail); } @@ -597,7 +595,7 @@ public class VcnManager { mExecutor.execute( () -> mCallback.onGatewayConnectionError( - new int[0], errorCode, cause))); + gatewayConnectionName, errorCode, cause))); } private static Throwable createThrowableByClassName( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java index 54cdeb8be5..8461de6d87 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnManagerTest.java @@ -211,7 +211,7 @@ public class VcnManagerTest { "exception_message"); verify(mMockStatusCallback) .onGatewayConnectionError( - any(int[].class), + eq(GATEWAY_CONNECTION_NAME), eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR), any(UnknownHostException.class)); } From 2f3de821dab73e5db608bf5a5834ff4321d94fd9 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 31 Mar 2021 10:43:23 -0700 Subject: [PATCH 0155/1057] Clarify docs for status codes in VcnStatusCallback. This CL clarifies the documentation for status codes used in VcnStatusCallback #onStatusChanged() and #onGatewayConnectionError, per API Council feedback. Bug: 182345902 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I86770a19f3d9f9a42aa3713489943fbe78561773 --- Vcn/framework-b/src/android/net/vcn/VcnManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index d09094cee1..344b20c036 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -437,7 +437,7 @@ public class VcnManager { * Invoked when status of the VCN for this callback's subscription group changes. * * @param statusCode the code for the status change encountered by this {@link - * VcnStatusCallback}'s subscription group. + * VcnStatusCallback}'s subscription group. This value will be one of VCN_STATUS_CODE_*. */ public abstract void onStatusChanged(@VcnStatusCode int statusCode); @@ -449,7 +449,8 @@ public class VcnManager { * encountering an error. This will match the name for exactly one {@link * VcnGatewayConnectionConfig} for the {@link VcnConfig} configured for this callback's * subscription group - * @param errorCode the code to indicate the error that occurred + * @param errorCode the code to indicate the error that occurred. This value will be one of + * VCN_ERROR_CODE_*. * @param detail Throwable to provide additional information about the error, or {@code * null} if none */ From 819d54c63e40b7bac2a8dd9e744924fd4bebadf1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 23 Mar 2021 12:26:09 -0700 Subject: [PATCH 0156/1057] Switch to using status codes for Vcn This change adds status codes, and switches the Vcn class to use these to signal safe mode status. Additionally, this allows a distinction between a VCN that is quitting and one that is simply in safe mode, providing potential for an opportunistic safe mode where the VCN will continue to attempt to serve NetworkRequests while not restricting underlying networks. Bug: 183174340 Bug: 181789060 Test: atest FrameworksVcnTests Change-Id: I9f2b2d0d8d7b3ade19ca5adcd48cc920171bf8c3 --- .../android/server/VcnManagementService.java | 27 +++++---- .../src/com/android/server/vcn/Vcn.java | 58 ++++++++++--------- .../server/VcnManagementServiceTest.java | 6 +- .../java/com/android/server/vcn/VcnTest.java | 22 +++---- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 434e9241c7..4fd9373ad1 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -40,7 +40,6 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; -import android.net.vcn.VcnManager; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; @@ -532,11 +531,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); - final boolean isActive = vcn.isActive(); + final int status = vcn.getStatus(); vcn.updateConfig(config); + // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode - if (!isActive) { + if (status == VCN_STATUS_CODE_SAFE_MODE) { // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback notifyAllPermissionedStatusCallbacksLocked( subscriptionGroup, VCN_STATUS_CODE_ACTIVE); @@ -769,7 +769,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final Vcn vcn = mVcns.get(subGrp); if (vcn != null) { - if (vcn.isActive()) { + if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) { isVcnManagedNetwork = true; } @@ -880,20 +880,23 @@ public class VcnManagementService extends IVcnManagementService.Stub { // now that callback is registered, send it the VCN's current status final VcnConfig vcnConfig = mConfigs.get(subGroup); final Vcn vcn = mVcns.get(subGroup); - final int vcnStatus; + final int vcnStatus = + vcn == null ? VCN_STATUS_CODE_NOT_CONFIGURED : vcn.getStatus(); + final int resultStatus; if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) { - vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; + resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } else if (vcn == null) { - vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE; - } else if (vcn.isActive()) { - vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE; + resultStatus = VCN_STATUS_CODE_INACTIVE; + } else if (vcnStatus == VCN_STATUS_CODE_ACTIVE + || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) { + resultStatus = vcnStatus; } else { - // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status - vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE; + Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus); + resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } try { - cbInfo.mCallback.onVcnStatusChanged(vcnStatus); + cbInfo.mCallback.onVcnStatusChanged(resultStatus); } catch (RemoteException e) { Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index c0130da7dd..5468935880 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -17,6 +17,9 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static com.android.server.VcnManagementService.VDBG; @@ -44,7 +47,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; /** * Represents an single instance of a VCN. @@ -137,17 +139,14 @@ public class Vcn extends Handler { @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; /** - * Whether this Vcn instance is active and running. + * The current status of this Vcn instance * - *

      The value will be {@code true} while running. It will be {@code false} if the VCN has been - * shut down or has entered safe mode. - * - *

      This AtomicBoolean is required in order to ensure consistency and correctness across - * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads - * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN - * Looper. + *

      The value will be {@link VCN_STATUS_CODE_ACTIVE} while all VcnGatewayConnections are in + * good standing, {@link VCN_STATUS_CODE_SAFE_MODE} if any VcnGatewayConnections are in safe + * mode, and {@link VCN_STATUS_CODE_INACTIVE} once a teardown has been commanded. */ - private final AtomicBoolean mIsActive = new AtomicBoolean(true); + // Accessed from different threads, but always under lock in VcnManagementService + private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE; public Vcn( @NonNull VcnContext vcnContext, @@ -199,9 +198,15 @@ public class Vcn extends Handler { sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); } - /** Synchronously checks whether this Vcn is active. */ - public boolean isActive() { - return mIsActive.get(); + /** Synchronously retrieves the current status code. */ + public int getStatus() { + return mCurrentStatus; + } + + /** Sets the status of this VCN */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setStatus(int status) { + mCurrentStatus = status; } /** Get current Gateways for testing purposes */ @@ -217,12 +222,6 @@ public class Vcn extends Handler { return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections)); } - /** Set whether this Vcn is active for testing purposes */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - public void setIsActive(boolean isActive) { - mIsActive.set(isActive); - } - private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { @@ -264,7 +263,8 @@ public class Vcn extends Handler { mConfig = config; - if (mIsActive.getAndSet(true)) { + // TODO(b/183174340): Remove this once opportunistic safe mode is supported. + if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { // VCN is already active - teardown any GatewayConnections whose configs have been // removed and get all current requests for (final Entry entry : @@ -288,11 +288,15 @@ public class Vcn extends Handler { // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be // satisfied start a new GatewayConnection) mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); - } else { + } else if (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) { // If this VCN was not previously active, it is exiting Safe Mode. Re-register the // request listener to get NetworkRequests again (and all cached requests). mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); + } else { + // Ignored; VCN was not active; config updates ignored. + return; } + mCurrentStatus = VCN_STATUS_CODE_ACTIVE; } private void handleTeardown() { @@ -302,18 +306,20 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } - mIsActive.set(false); + mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } private void handleEnterSafeMode() { + // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported handleTeardown(); + mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE; mVcnCallback.onEnteredSafeMode(); } private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { - if (!isActive()) { + if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) { Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now"); return; } @@ -370,8 +376,8 @@ public class Vcn extends Handler { mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied - // start a new GatewayConnection), but only if the Vcn is still active - if (isActive()) { + // start a new GatewayConnection), but only if the Vcn is still alive + if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); } } @@ -379,7 +385,7 @@ public class Vcn extends Handler { private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; - if (isActive()) { + if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index c88b0c1547..4ad7136aab 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -19,6 +19,8 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -695,7 +697,9 @@ public class VcnManagementServiceTest { hasCarrierPrivileges); final Vcn vcn = startAndGetVcnInstance(subGrp); - doReturn(isVcnActive).when(vcn).isActive(); + doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE) + .when(vcn) + .getStatus(); doReturn(true) .when(mLocationPermissionChecker) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 530d8348bf..540be38ed7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -19,10 +19,12 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; @@ -142,7 +144,7 @@ public class VcnTest { mTestLooper.dispatchAll(); } - private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) { + private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); @@ -152,25 +154,25 @@ public class VcnTest { final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); - mVcn.setIsActive(isActive); + mVcn.setStatus(status); mVcn.updateSubscriptionSnapshot(updatedSnapshot); mTestLooper.dispatchAll(); for (final VcnGatewayConnection gateway : gatewayConnections) { - verify(gateway, isActive ? times(1) : never()) + verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never()) .updateSubscriptionSnapshot(eq(updatedSnapshot)); } } @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { - verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */); + verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE); } @Test - public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() { - verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */); + public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() { + verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE); } private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { @@ -201,7 +203,7 @@ public class VcnTest { private void verifySafeMode( NetworkRequestListener requestListener, Set expectedGatewaysTornDown) { - assertFalse(mVcn.isActive()); + assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus()); for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { verify(gatewayConnection).teardownAsynchronously(); } @@ -319,7 +321,7 @@ public class VcnTest { // Registered on start, then re-registered with new configs verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); - assertTrue(mVcn.isActive()); + assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus()); for (final int[] caps : TEST_CAPS) { // Expect each gateway connection created only on initial startup verify(mDeps) @@ -334,7 +336,7 @@ public class VcnTest { @Test public void testIgnoreNetworkRequestWhileInactive() { - mVcn.setIsActive(false /* isActive */); + mVcn.setStatus(VCN_STATUS_CODE_INACTIVE); final NetworkRequestListener requestListener = verifyAndGetRequestListener(); triggerVcnRequestListeners(requestListener); From d3658ad13eaa8fa0411276c02a8d6826a0b2f2b5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 31 Mar 2021 13:16:07 -0700 Subject: [PATCH 0157/1057] Remove subIds from Telephony NetworkRequests. Since NetworkProviders do not at present support requests with subIds (they always provide an empty list, therefore never have an overlap), the TelephonyBringupRequests must never present subIds as part of the requested capabilities. Bug: 183174340 Test: atest FrameworksVcnTests Change-Id: I2e52ff67748c0ca226a648682b37dfe0996cb850 --- .../server/vcn/UnderlyingNetworkTracker.java | 51 +++++++++++++++---- .../vcn/UnderlyingNetworkTrackerTest.java | 16 +++--- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 069c5c3fc7..ab9de77005 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -118,7 +118,7 @@ public class UnderlyingNetworkTracker { if (!mIsQuitting) { mRouteSelectionCallback = new RouteSelectionCallback(); mConnectivityManager.requestBackgroundNetwork( - getBaseNetworkRequestBuilder().build(), mHandler, mRouteSelectionCallback); + getRouteSelectionRequest(), mHandler, mRouteSelectionCallback); mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( @@ -149,12 +149,48 @@ public class UnderlyingNetworkTracker { } } - private NetworkRequest getWifiNetworkRequest() { + /** + * Builds the Route selection request + * + *

      This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue + * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier + * owned networks may be selected, as the request specifies only subIds in the VCN's + * subscription group, while the VCN networks are excluded by virtue of not having subIds set on + * the VCN-exposed networks. + */ + private NetworkRequest getRouteSelectionRequest() { return getBaseNetworkRequestBuilder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } + /** + * Builds the WiFi bringup request + * + *

      This request is built specifically to match only carrier-owned WiFi networks, but is also + * built to ONLY keep Carrier WiFi Networks alive (but never bring them up). This is a result of + * the WifiNetworkFactory not advertising a list of subIds, and therefore not accepting this + * request. As such, it will bind to a Carrier WiFi Network that has already been brought up, + * but will NEVER bring up a Carrier WiFi network itself. + */ + private NetworkRequest getWifiNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + .build(); + } + + /** + * Builds a Cellular bringup request for a given subId + * + *

      This request is filed in order to ensure that the Telephony stack always has a + * NetworkRequest to bring up a VCN underlying cellular network. It is required in order to + * ensure that even when a VCN (appears as Cellular) satisfies the default request, Telephony + * will bring up additional underlying Cellular networks. + * + *

      Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified + * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier. + */ private NetworkRequest getCellNetworkRequestForSubId(int subId) { return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) @@ -164,20 +200,13 @@ public class UnderlyingNetworkTracker { /** * Builds and returns a NetworkRequest builder common to all Underlying Network requests - * - *

      This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue - * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier - * owned networks may be selected, as the request specifies only subIds in the VCN's - * subscription group, while the VCN networks are excluded by virtue of not having subIds set on - * the VCN-exposed networks. */ private NetworkRequest.Builder getBaseNetworkRequestBuilder() { return new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index ed2e4d9b99..b592000e38 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -158,7 +158,7 @@ public class UnderlyingNetworkTrackerTest { for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getCellRequestForSubId(subId, expectedSubIds)), + eq(getCellRequestForSubId(subId)), any(), any(NetworkBringupCallback.class)); } @@ -189,30 +189,30 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getWifiRequest(Set netCapsSubIds) { - return getExpectedRequestBase(netCapsSubIds) + return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubIds(netCapsSubIds) .build(); } - private NetworkRequest getCellRequestForSubId(int subId, Set netCapsSubIds) { - return getExpectedRequestBase(netCapsSubIds) + private NetworkRequest getCellRequestForSubId(int subId) { + return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { - return getExpectedRequestBase(netCapsSubIds).build(); + return getExpectedRequestBase().setSubIds(netCapsSubIds).build(); } - private NetworkRequest.Builder getExpectedRequestBase(Set subIds) { + private NetworkRequest.Builder getExpectedRequestBase() { final NetworkRequest.Builder builder = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .setSubIds(subIds); + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); return builder; } From 0f07af5cf214a0765bc42773ab88a695e03f298c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 31 Mar 2021 11:00:37 -0700 Subject: [PATCH 0158/1057] Prevent changes to immutable capabilities for carrier wifi This change prevents carrier wifi from having changes to the RESTRICTED network capability, which is an immutable capability. Bug: 184101137 Test: atest FrameworksVcnTests Change-Id: I802d36a754d961c9928a2e642e25f1b25b8be12d --- .../android/server/VcnManagementService.java | 57 ++++++++++++++- .../server/VcnManagementServiceTest.java | 72 +++++++++++++++++-- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 4fd9373ad1..46f4b0b41a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; @@ -35,7 +37,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -161,6 +165,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnContext mVcnContext; @NonNull private final BroadcastReceiver mPkgChangeReceiver; + @NonNull + private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback(); + /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */ @Nullable private LocationPermissionChecker mLocationPermissionChecker; @@ -357,6 +364,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void systemReady() { mContext.getSystemService(ConnectivityManager.class) .registerNetworkProvider(mNetworkProvider); + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mTrackingNetworkCallback); mTelephonySubscriptionTracker.register(); mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext()); } @@ -792,8 +803,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } + final NetworkCapabilities result = ncBuilder.build(); return new VcnUnderlyingNetworkPolicy( - false /* isTearDownRequested */, ncBuilder.build()); + mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result); }); } @@ -940,6 +952,49 @@ public class VcnManagementService extends IVcnManagementService.Stub { @Nullable String exceptionMessage); } + /** + * TrackingNetworkCallback tracks all active networks + * + *

      This is used to ensure that no underlying networks have immutable capabilities changed + * without requiring a Network restart. + */ + private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback { + private final Map mCaps = new ArrayMap<>(); + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) { + synchronized (mCaps) { + mCaps.put(network, caps); + } + } + + @Override + public void onLost(Network network) { + synchronized (mCaps) { + mCaps.remove(network); + } + } + + private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) { + if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) { + return false; + } + + synchronized (mCaps) { + for (NetworkCapabilities existing : mCaps.values()) { + if (existing.hasTransport(TRANSPORT_WIFI) + && caps.getSubIds().equals(existing.getSubIds())) { + // Restart if any immutable capabilities have changed + return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); + } + } + } + + return false; + } + } + /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */ private class VcnCallbackImpl implements VcnCallback { @NonNull private final ParcelUuid mSubGroup; diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4ad7136aab..4ffbf3147e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.net.ConnectivityManager.NetworkCallback; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -55,8 +57,10 @@ import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkCapabilities.Transport; +import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -258,6 +262,10 @@ public class VcnManagementServiceTest { verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); + verify(mConnMgr) + .registerNetworkCallback( + eq(new NetworkRequest.Builder().clearCapabilities().build()), + any(NetworkCallback.class)); } @Test @@ -706,10 +714,8 @@ public class VcnManagementServiceTest { .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); } - private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport( - int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) { - setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); - + private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport( + int subId, int transport) { final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder() .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) @@ -718,7 +724,16 @@ public class VcnManagementServiceTest { ncBuilder.setSubIds(Collections.singleton(subId)); } - return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties()); + return ncBuilder; + } + + private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport( + int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) { + setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); + + return mVcnMgmtSvc.getUnderlyingNetworkPolicy( + getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), + new LinkProperties()); } @Test @@ -780,6 +795,53 @@ public class VcnManagementServiceTest { true /* isRestricted */); } + private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { + mVcnMgmtSvc.systemReady(); + + final ArgumentCaptor captor = + ArgumentCaptor.forClass(NetworkCallback.class); + verify(mConnMgr) + .registerNetworkCallback( + eq(new NetworkRequest.Builder().clearCapabilities().build()), + captor.capture()); + captor.getValue().onCapabilitiesChanged(new Network(0), caps); + } + + @Test + public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart() + throws Exception { + final NetworkCapabilities existingNetworkCaps = + getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(); + setupTrackedCarrierWifiNetwork(existingNetworkCaps); + + // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED + // immutable capability + final VcnUnderlyingNetworkPolicy policy = + mVcnMgmtSvc.getUnderlyingNetworkPolicy( + getNetworkCapabilitiesBuilderForTransport( + TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) + .build(), + new LinkProperties()); + assertTrue(policy.isTeardownRequested()); + } + + @Test + public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart() + throws Exception { + final NetworkCapabilities existingNetworkCaps = + getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) + .build(); + setupTrackedCarrierWifiNetwork(existingNetworkCaps); + + final VcnUnderlyingNetworkPolicy policy = + startVcnAndGetPolicyForTransport( + TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI); + + assertTrue(policy.isTeardownRequested()); + } + @Test public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception { setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */); From c6d240b044a5588f6fa0f6b3d6f1bbce639cd47d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 23 Mar 2021 01:26:17 -0700 Subject: [PATCH 0159/1057] Allow soft-start and opportunistic safe mode This change adds support for opportunistic safe mode, where the VCN will continue to provide networks, but not restrict underlying networks. Similarly, this change allows for soft-starting of the VCN, where VCN underlying networks can be selected without restricting them directly. Additionally, this change ensures networks are torn down when VcnGatewayConnections enter safe mode. This change is required due to changes in the lifecycle of the VcnGatwayConnection, where in safe mode they are NOT torn down, but allowed to continue retrying. During these broken-connectivity windows, the VCN network should be torn down to prevent blackholing traffic. Bug: 183174340 Test: atest FrameworksVcnTests Change-Id: I50f2c0e92552281731c843db89e9a9a1ccff5346 --- .../android/server/VcnManagementService.java | 20 +-- .../src/com/android/server/vcn/Vcn.java | 126 +++++++++--------- .../server/vcn/VcnGatewayConnection.java | 119 +++++++++++++---- .../server/VcnManagementServiceTest.java | 52 ++++---- ...cnGatewayConnectionConnectedStateTest.java | 72 ++++++++-- ...nGatewayConnectionConnectingStateTest.java | 5 +- ...tewayConnectionDisconnectingStateTest.java | 5 +- ...atewayConnectionRetryTimeoutStateTest.java | 5 +- .../vcn/VcnGatewayConnectionTestBase.java | 16 ++- .../java/com/android/server/vcn/VcnTest.java | 120 ++++++----------- 10 files changed, 314 insertions(+), 226 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 46f4b0b41a..f7ae58ca0e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -542,16 +542,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); - final int status = vcn.getStatus(); vcn.updateConfig(config); - - // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported - // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode - if (status == VCN_STATUS_CODE_SAFE_MODE) { - // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - subscriptionGroup, VCN_STATUS_CODE_ACTIVE); - } } else { startVcnLocked(subscriptionGroup, config); } @@ -941,8 +932,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService /** Callback for Vcn signals sent up to VcnManagementService. */ public interface VcnCallback { - /** Called by a Vcn to signal that it has entered safe mode. */ - void onEnteredSafeMode(); + /** Called by a Vcn to signal that its safe mode status has changed. */ + void onSafeModeStatusChanged(boolean isInSafeMode); /** Called by a Vcn to signal that an error occurred. */ void onGatewayConnectionError( @@ -1004,15 +995,18 @@ public class VcnManagementService extends IVcnManagementService.Stub { } @Override - public void onEnteredSafeMode() { + public void onSafeModeStatusChanged(boolean isInSafeMode) { synchronized (mLock) { // Ignore if this subscription group doesn't exist anymore if (!mVcns.containsKey(mSubGroup)) { return; } + final int status = + isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; + notifyAllPolicyListenersLocked(); - notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE); + notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 5468935880..ca7289fd54 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -96,17 +96,21 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3; + /** + * Triggers reevaluation of safe mode conditions. + * + *

      Upon entering safe mode, the VCN will only provide gateway connections opportunistically, + * leaving the underlying networks marked as NOT_VCN_MANAGED. + * + *

      Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put + * into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to + * determine if any are in safe mode. + */ + private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; - /** - * Causes this VCN to immediately enter safe mode. - * - *

      Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its - * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode. - */ - private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1; - @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Dependencies mDeps; @@ -233,6 +237,11 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { + if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE + && mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) { + return; + } + switch (msg.what) { case MSG_EVENT_CONFIG_UPDATED: handleConfigUpdated((VcnConfig) msg.obj); @@ -246,12 +255,12 @@ public class Vcn extends Handler { case MSG_EVENT_GATEWAY_CONNECTION_QUIT: handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj); break; + case MSG_EVENT_SAFE_MODE_STATE_CHANGED: + handleSafeModeStatusChanged(); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; - case MSG_CMD_ENTER_SAFE_MODE: - handleEnterSafeMode(); - break; default: Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); } @@ -263,40 +272,28 @@ public class Vcn extends Handler { mConfig = config; - // TODO(b/183174340): Remove this once opportunistic safe mode is supported. - if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { - // VCN is already active - teardown any GatewayConnections whose configs have been - // removed and get all current requests - for (final Entry entry : - mVcnGatewayConnections.entrySet()) { - final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); - final VcnGatewayConnection gatewayConnection = entry.getValue(); + // Teardown any GatewayConnections whose configs have been removed and get all current + // requests + for (final Entry entry : + mVcnGatewayConnections.entrySet()) { + final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); + final VcnGatewayConnection gatewayConnection = entry.getValue(); - // GatewayConnectionConfigs must match exactly (otherwise authentication or - // connection details may have changed). - if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { - if (gatewayConnection == null) { - Slog.wtf( - getLogTag(), - "Found gatewayConnectionConfig without GatewayConnection"); - } else { - gatewayConnection.teardownAsynchronously(); - } + // GatewayConnectionConfigs must match exactly (otherwise authentication or + // connection details may have changed). + if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { + if (gatewayConnection == null) { + Slog.wtf( + getLogTag(), "Found gatewayConnectionConfig without GatewayConnection"); + } else { + gatewayConnection.teardownAsynchronously(); } } - - // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be - // satisfied start a new GatewayConnection) - mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); - } else if (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) { - // If this VCN was not previously active, it is exiting Safe Mode. Re-register the - // request listener to get NetworkRequests again (and all cached requests). - mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); - } else { - // Ignored; VCN was not active; config updates ignored. - return; } - mCurrentStatus = VCN_STATUS_CODE_ACTIVE; + + // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be + // satisfied start a new GatewayConnection) + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); } private void handleTeardown() { @@ -309,21 +306,27 @@ public class Vcn extends Handler { mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } - private void handleEnterSafeMode() { - // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported - handleTeardown(); + private void handleSafeModeStatusChanged() { + boolean hasSafeModeGatewayConnection = false; - mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE; - mVcnCallback.onEnteredSafeMode(); + // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode + for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { + if (gatewayConnection.isInSafeMode()) { + hasSafeModeGatewayConnection = true; + break; + } + } + + final int oldStatus = mCurrentStatus; + mCurrentStatus = + hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; + if (oldStatus != mCurrentStatus) { + mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); + } } private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { - if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) { - Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now"); - return; - } - if (score > getNetworkScore()) { if (VDBG) { Slog.v( @@ -376,19 +379,16 @@ public class Vcn extends Handler { mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied - // start a new GatewayConnection), but only if the Vcn is still alive - if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { - mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); - } + // start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check + // in handleMessage() + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); } private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; - if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { - for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { - gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); - } + for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { + gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } } @@ -418,8 +418,8 @@ public class Vcn extends Handler { /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ @VisibleForTesting(visibility = Visibility.PACKAGE) public interface VcnGatewayStatusCallback { - /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */ - void onEnteredSafeMode(); + /** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */ + void onSafeModeStatusChanged(); /** Callback by a VcnGatewayConnection to indicate that an error occurred. */ void onGatewayConnectionError( @@ -445,8 +445,8 @@ public class Vcn extends Handler { } @Override - public void onEnteredSafeMode() { - sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); + public void onSafeModeStatusChanged() { + sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED)); } @Override diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 2ba8edd3b1..1780260d36 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -44,6 +44,7 @@ import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; +import android.net.NetworkProvider; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; @@ -92,6 +93,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; /** * A single VCN Gateway Connection, providing a single public-facing VCN network. @@ -503,6 +505,15 @@ public class VcnGatewayConnection extends StateMachine { */ private boolean mIsQuitting = false; + /** + * Whether the VcnGatewayConnection is in safe mode. + * + *

      Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this + * VcnGatewayConnection will continue attempting to connect, and if a successful connection is + * made, safe mode will be exited. + */ + private boolean mIsInSafeMode = false; + /** * The token used by the primary/current/active session. * @@ -562,8 +573,7 @@ public class VcnGatewayConnection extends StateMachine { *

      Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable * otherwise. */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - NetworkAgent mNetworkAgent; + private NetworkAgent mNetworkAgent; @Nullable private WakeupMessage mTeardownTimeoutAlarm; @Nullable private WakeupMessage mDisconnectRequestAlarm; @@ -628,6 +638,14 @@ public class VcnGatewayConnection extends StateMachine { start(); } + /** Queries whether this VcnGatewayConnection is in safe mode. */ + public boolean isInSafeMode() { + // Accessing internal state; must only be done on looper thread. + mVcnContext.ensureRunningOnLooperThread(); + + return mIsInSafeMode; + } + /** * Asynchronously tears down this GatewayConnection, and any resources used. * @@ -1162,6 +1180,15 @@ public class VcnGatewayConnection extends StateMachine { } } + protected void handleSafeModeTimeoutExceeded() { + mSafeModeTimeoutAlarm = null; + + // Connectivity for this GatewayConnection is broken; tear down the Network. + teardownNetwork(); + mIsInSafeMode = true; + mGatewayStatusCallback.onSafeModeStatusChanged(); + } + protected void logUnexpectedEvent(int what) { Slog.d(TAG, String.format( "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); @@ -1315,8 +1342,7 @@ public class VcnGatewayConnection extends StateMachine { } break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafeMode(); - mSafeModeTimeoutAlarm = null; + handleSafeModeTimeoutExceeded(); break; default: logUnhandledMessage(msg); @@ -1401,8 +1427,7 @@ public class VcnGatewayConnection extends StateMachine { handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafeMode(); - mSafeModeTimeoutAlarm = null; + handleSafeModeTimeoutExceeded(); break; default: logUnhandledMessage(msg); @@ -1434,28 +1459,23 @@ public class VcnGatewayConnection extends StateMachine { buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); final NetworkAgent agent = - new NetworkAgent( - mVcnContext.getContext(), - mVcnContext.getLooper(), + mDeps.newNetworkAgent( + mVcnContext, TAG, caps, lp, Vcn.getNetworkScore(), new NetworkAgentConfig.Builder().build(), - mVcnContext.getVcnNetworkProvider()) { - @Override - public void onNetworkUnwanted() { - Slog.d(TAG, "NetworkAgent was unwanted"); - teardownAsynchronously(); - } - - @Override - public void onValidationStatus(int status, @Nullable Uri redirectUri) { - if (status == NetworkAgent.VALIDATION_STATUS_VALID) { - clearFailedAttemptCounterAndSafeModeAlarm(); - } - } - }; + mVcnContext.getVcnNetworkProvider(), + () -> { + Slog.d(TAG, "NetworkAgent was unwanted"); + teardownAsynchronously(); + } /* networkUnwantedCallback */, + (status) -> { + if (status == NetworkAgent.VALIDATION_STATUS_VALID) { + clearFailedAttemptCounterAndSafeModeAlarm(); + } + } /* validationStatusCallback */); agent.register(); agent.markConnected(); @@ -1469,6 +1489,11 @@ public class VcnGatewayConnection extends StateMachine { // Validated connection, clear failed attempt counter mFailedAttempts = 0; cancelSafeModeAlarm(); + + if (mIsInSafeMode) { + mIsInSafeMode = false; + mGatewayStatusCallback.onSafeModeStatusChanged(); + } } protected void applyTransform( @@ -1587,8 +1612,7 @@ public class VcnGatewayConnection extends StateMachine { handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafeMode(); - mSafeModeTimeoutAlarm = null; + handleSafeModeTimeoutExceeded(); break; default: logUnhandledMessage(msg); @@ -1692,8 +1716,7 @@ public class VcnGatewayConnection extends StateMachine { handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: - mGatewayStatusCallback.onEnteredSafeMode(); - mSafeModeTimeoutAlarm = null; + handleSafeModeTimeoutExceeded(); break; default: logUnhandledMessage(msg); @@ -1934,6 +1957,16 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = session; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + NetworkAgent getNetworkAgent() { + return mNetworkAgent; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setNetworkAgent(@Nullable NetworkAgent networkAgent) { + mNetworkAgent = networkAgent; + } + @VisibleForTesting(visibility = Visibility.PRIVATE) void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) { sendMessageAndAcquireWakeLock( @@ -2018,6 +2051,38 @@ public class VcnGatewayConnection extends StateMachine { return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable); } + /** Builds a new NetworkAgent. */ + public NetworkAgent newNetworkAgent( + @NonNull VcnContext vcnContext, + @NonNull String tag, + @NonNull NetworkCapabilities caps, + @NonNull LinkProperties lp, + @NonNull int score, + @NonNull NetworkAgentConfig nac, + @NonNull NetworkProvider provider, + @NonNull Runnable networkUnwantedCallback, + @NonNull Consumer validationStatusCallback) { + return new NetworkAgent( + vcnContext.getContext(), + vcnContext.getLooper(), + tag, + caps, + lp, + score, + nac, + provider) { + @Override + public void onNetworkUnwanted() { + networkUnwantedCallback.run(); + } + + @Override + public void onValidationStatus(int status, @Nullable Uri redirectUri) { + validationStatusCallback.accept(status); + } + }; + } + /** Gets the elapsed real time since boot, in millis. */ public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4ffbf3147e..43e6676e1d 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -536,17 +536,6 @@ public class VcnManagementServiceTest { verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); } - @Test - public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception { - setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */); - mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); - verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); - - mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); - - verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); - } - @Test public void testClearVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -902,7 +891,9 @@ public class VcnManagementServiceTest { } private void triggerVcnSafeMode( - @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) + @NonNull ParcelUuid subGroup, + @NonNull TelephonySubscriptionSnapshot snapshot, + boolean isInSafeMode) throws Exception { verify(mMockDeps) .newVcn( @@ -913,22 +904,32 @@ public class VcnManagementServiceTest { mVcnCallbackCaptor.capture()); VcnCallback vcnCallback = mVcnCallbackCaptor.getValue(); - vcnCallback.onEnteredSafeMode(); + vcnCallback.onSafeModeStatusChanged(isInSafeMode); } - @Test - public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception { + private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode) + throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - triggerVcnSafeMode(TEST_UUID_1, snapshot); + triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode); verify(mMockPolicyListener).onPolicyChanged(); } - private void triggerVcnStatusCallbackOnEnteredSafeMode( + @Test + public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception { + verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */); + } + + @Test + public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception { + verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */); + } + + private void triggerVcnStatusCallbackOnSafeModeStatusChanged( @NonNull ParcelUuid subGroup, @NonNull String pkgName, int uid, @@ -951,12 +952,13 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); - triggerVcnSafeMode(subGroup, snapshot); + triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */); } @Test - public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception { - triggerVcnStatusCallbackOnEnteredSafeMode( + public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges() + throws Exception { + triggerVcnStatusCallbackOnSafeModeStatusChanged( TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, @@ -967,8 +969,9 @@ public class VcnManagementServiceTest { } @Test - public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception { - triggerVcnStatusCallbackOnEnteredSafeMode( + public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges() + throws Exception { + triggerVcnStatusCallbackOnSafeModeStatusChanged( TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, @@ -980,8 +983,9 @@ public class VcnManagementServiceTest { } @Test - public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception { - triggerVcnStatusCallbackOnEnteredSafeMode( + public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission() + throws Exception { + triggerVcnStatusCallbackOnSafeModeStatusChanged( TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 2fadd44440..fdd7e3e6bd 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -60,17 +60,24 @@ import org.mockito.ArgumentCaptor; import java.io.IOException; import java.net.UnknownHostException; import java.util.Collections; +import java.util.function.Consumer; /** Tests for VcnGatewayConnection.ConnectedState */ @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { private VcnIkeSession mIkeSession; + private NetworkAgent mNetworkAgent; @Before public void setUp() throws Exception { super.setUp(); + mNetworkAgent = mock(NetworkAgent.class); + doReturn(mNetworkAgent) + .when(mDeps) + .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any()); + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); @@ -159,11 +166,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } - @Test - public void testChildOpenedRegistersNetwork() throws Exception { - // Verify scheduled but not canceled when entering ConnectedState - verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); - + private void triggerChildOpened() { final VcnChildSessionConfiguration mMockChildSessionConfig = mock(VcnChildSessionConfiguration.class); doReturn(Collections.singletonList(TEST_INTERNAL_ADDR)) @@ -174,6 +177,31 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .getInternalDnsServers(); getChildSessionCallback().onOpened(mMockChildSessionConfig); + } + + private void triggerValidation(int status) { + final ArgumentCaptor> validationCallbackCaptor = + ArgumentCaptor.forClass(Consumer.class); + verify(mDeps) + .newNetworkAgent( + any(), + any(), + any(), + any(), + anyInt(), + any(), + any(), + any(), + validationCallbackCaptor.capture()); + + validationCallbackCaptor.getValue().accept(status); + } + + @Test + public void testChildOpenedRegistersNetwork() throws Exception { + // Verify scheduled but not canceled when entering ConnectedState + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + triggerChildOpened(); mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); @@ -182,15 +210,20 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection ArgumentCaptor.forClass(LinkProperties.class); final ArgumentCaptor ncCaptor = ArgumentCaptor.forClass(NetworkCapabilities.class); - verify(mConnMgr) - .registerNetworkAgent( - any(), - any(), - lpCaptor.capture(), + verify(mDeps) + .newNetworkAgent( + eq(mVcnContext), + any(String.class), ncCaptor.capture(), + lpCaptor.capture(), + anyInt(), any(), any(), - anyInt()); + any(), + any()); + verify(mNetworkAgent).register(); + verify(mNetworkAgent).markConnected(); + verify(mIpSecSvc) .addAddressToTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any()); @@ -208,9 +241,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is // canceled - mGatewayConnection.mNetworkAgent.onValidationStatus( - NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */); + triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); verify(mSafeModeTimeoutAlarm).cancel(); + assertFalse(mGatewayConnection.isInSafeMode()); + } + + @Test + public void testSuccessfulConnectionExitsSafeMode() throws Exception { + verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( + mGatewayConnection.mConnectedState); + + triggerChildOpened(); + mTestLooper.dispatchAll(); + + triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + + assertFalse(mGatewayConnection.isInSafeMode()); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 7afa4494ee..bfe8c73d63 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -118,8 +118,9 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio } @Test - public void testSafeModeTimeoutNotifiesCallback() { - verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); + public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() { + verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( + mGatewayConnection.mConnectingState); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 99feffdebc..9da8b451c9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -86,8 +86,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec } @Test - public void testSafeModeTimeoutNotifiesCallback() { - verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); + public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() { + verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( + mGatewayConnection.mDisconnectingState); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 85a0277f8b..6dbf7d552b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -96,8 +96,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect } @Test - public void testSafeModeTimeoutNotifiesCallback() { - verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); + public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() { + verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( + mGatewayConnection.mRetryTimeoutState); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index a660735470..884b2338d8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -21,6 +21,8 @@ import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; @@ -42,6 +44,7 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; @@ -267,7 +270,12 @@ public class VcnGatewayConnectionTestBase { expectCanceled); } - protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) { + protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( + @NonNull State expectedState) { + // Set a NetworkAgent, and expect it to be unregistered and cleared + final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class); + mGatewayConnection.setNetworkAgent(mockNetworkAgent); + // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial // state) final Runnable delayedEvent = @@ -275,7 +283,11 @@ public class VcnGatewayConnectionTestBase { delayedEvent.run(); mTestLooper.dispatchAll(); - verify(mGatewayStatusCallback).onEnteredSafeMode(); + verify(mGatewayStatusCallback).onSafeModeStatusChanged(); assertEquals(expectedState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isInSafeMode()); + + verify(mockNetworkAgent).unregister(); + assertNull(mGatewayConnection.getNetworkAgent()); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 540be38ed7..9dc14b68ba 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -20,13 +20,11 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; -import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -54,7 +52,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.UUID; @@ -160,8 +157,7 @@ public class VcnTest { mTestLooper.dispatchAll(); for (final VcnGatewayConnection gateway : gatewayConnections) { - verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never()) - .updateSubscriptionSnapshot(eq(updatedSnapshot)); + verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot)); } } @@ -202,32 +198,53 @@ public class VcnTest { private void verifySafeMode( NetworkRequestListener requestListener, - Set expectedGatewaysTornDown) { - assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus()); - for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { - verify(gatewayConnection).teardownAsynchronously(); + Set activeGateways, + boolean expectInSafeMode) { + for (VcnGatewayConnection gatewayConnection : activeGateways) { + verify(gatewayConnection, never()).teardownAsynchronously(); } - verify(mVcnNetworkProvider).unregisterListener(requestListener); - verify(mVcnCallback).onEnteredSafeMode(); + + assertEquals( + expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE, + mVcn.getStatus()); + verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode); } @Test - public void testGatewayEnteringSafeModeNotifiesVcn() { + public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final Set gatewayConnections = startGatewaysAndGetGatewayConnections(requestListener); - // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down - // all Gateways + // Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway + // entering Safemode should trigger safe mode final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); - statusCallback.onEnteredSafeMode(); + final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next(); + + doReturn(true).when(gatewayConnection).isInSafeMode(); + statusCallback.onSafeModeStatusChanged(); mTestLooper.dispatchAll(); - verifySafeMode(requestListener, gatewayConnections); + verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */); + + // Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode + doReturn(false).when(gatewayConnection).isInSafeMode(); + statusCallback.onSafeModeStatusChanged(); + mTestLooper.dispatchAll(); + + verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */); + + // Re-trigger, verify safe mode callback does not get fired again for identical state + statusCallback.onSafeModeStatusChanged(); + mTestLooper.dispatchAll(); + + // Expect only once still; from above. + verify(mVcnCallback).onSafeModeStatusChanged(false); } - @Test - public void testGatewayQuit() { + private void verifyGatewayQuit(int status) { + mVcn.setStatus(status); + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final Set gatewayConnections = new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); @@ -240,7 +257,7 @@ public class VcnTest { assertEquals(1, mVcn.getVcnGatewayConnections().size()); verify(mVcnNetworkProvider).resendAllRequests(requestListener); - // Verify that the VcnGatewayConnection is restarted + // Verify that the VcnGatewayConnection is restarted if a request exists for it triggerVcnRequestListeners(requestListener); mTestLooper.dispatchAll(); assertEquals(2, mVcn.getVcnGatewayConnections().size()); @@ -254,21 +271,13 @@ public class VcnTest { } @Test - public void testGatewayQuitWhileInactive() { - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - final Set gatewayConnections = - new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + public void testGatewayQuitReevaluatesRequests() { + verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE); + } - mVcn.teardownAsynchronously(); - mTestLooper.dispatchAll(); - - final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); - statusCallback.onQuit(); - mTestLooper.dispatchAll(); - - // Verify that the VCN requests the networkRequests be resent - assertEquals(1, mVcn.getVcnGatewayConnections().size()); - verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener); + @Test + public void testGatewayQuitReevaluatesRequestsInSafeMode() { + verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -298,49 +307,4 @@ public class VcnTest { verify(removedGatewayConnection).teardownAsynchronously(); verify(mVcnNetworkProvider).resendAllRequests(requestListener); } - - @Test - public void testUpdateConfigExitsSafeMode() { - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - final Set gatewayConnections = - new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); - - final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); - statusCallback.onEnteredSafeMode(); - mTestLooper.dispatchAll(); - verifySafeMode(requestListener, gatewayConnections); - - doAnswer(invocation -> { - final NetworkRequestListener listener = invocation.getArgument(0); - triggerVcnRequestListeners(listener); - return null; - }).when(mVcnNetworkProvider).registerListener(eq(requestListener)); - - mVcn.updateConfig(mConfig); - mTestLooper.dispatchAll(); - - // Registered on start, then re-registered with new configs - verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); - assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus()); - for (final int[] caps : TEST_CAPS) { - // Expect each gateway connection created only on initial startup - verify(mDeps) - .newVcnGatewayConnection( - eq(mVcnContext), - eq(TEST_SUB_GROUP), - eq(mSubscriptionSnapshot), - argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())), - any()); - } - } - - @Test - public void testIgnoreNetworkRequestWhileInactive() { - mVcn.setStatus(VCN_STATUS_CODE_INACTIVE); - - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - triggerVcnRequestListeners(requestListener); - - verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any()); - } } From 8e97e849e734b22ae534d74fe4c56297759d787b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Apr 2021 14:09:02 -0700 Subject: [PATCH 0160/1057] Add TRANSPORT_CELLULAR to VCN filter This change adds the CELLULAR transport to the filter used by the Vcn to determine if a configuration can satisfy a given NetworkRequest Bug: 184101137 Test: atest FrameworksVcnTests Change-Id: I7df3f14b5ef66551728b398fd4a9e233d1df4706 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 2 ++ Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index ca7289fd54..ae806aa500 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -17,6 +17,7 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; @@ -395,6 +396,7 @@ public class Vcn extends Handler { private boolean isRequestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); + builder.addTransportType(TRANSPORT_CELLULAR); builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); for (int cap : config.getAllExposedCapabilities()) { builder.addCapability(cap); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 9dc14b68ba..90eb75e865 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -19,6 +19,7 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; @@ -133,6 +134,7 @@ public class VcnTest { private void startVcnGatewayWithCapabilities( NetworkRequestListener requestListener, int... netCapabilities) { final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); + requestBuilder.addTransportType(TRANSPORT_CELLULAR); for (final int netCapability : netCapabilities) { requestBuilder.addCapability(netCapability); } From 3d241adaf97af138d543a4dc40ed4bff63a99d26 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Apr 2021 16:58:27 -0700 Subject: [PATCH 0161/1057] Populate legacy type in VCN NetworkAgentConfig This change ensures that the VCN populates the legacy type field, otherwise ConnectivityService crashes on an unknown legacy type. Bug: 184304972 Test: atest FrameworksVcnTests Change-Id: I59dc46dc34d2812a6c8f73c72d208fa735791d74 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 7 ++++++- .../server/vcn/VcnGatewayConnectionConnectedStateTest.java | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 1780260d36..eed2006382 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -32,6 +32,7 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; @@ -1457,6 +1458,10 @@ public class VcnGatewayConnection extends StateMachine { buildNetworkCapabilities(mConnectionConfig, mUnderlying); final LinkProperties lp = buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); + final NetworkAgentConfig nac = + new NetworkAgentConfig.Builder() + .setLegacyType(ConnectivityManager.TYPE_MOBILE) + .build(); final NetworkAgent agent = mDeps.newNetworkAgent( @@ -1465,7 +1470,7 @@ public class VcnGatewayConnection extends StateMachine { caps, lp, Vcn.getNetworkScore(), - new NetworkAgentConfig.Builder().build(), + nac, mVcnContext.getVcnNetworkProvider(), () -> { Slog.d(TAG, "NetworkAgent was unwanted"); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index fdd7e3e6bd..3b0be301ed 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -40,6 +41,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; @@ -217,7 +219,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection ncCaptor.capture(), lpCaptor.capture(), anyInt(), - any(), + argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE), any(), any(), any()); From aa897c2bd069d154f978b162dbef6d8f8096f334 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Apr 2021 18:23:45 -0700 Subject: [PATCH 0162/1057] Add/remove internal addresses from IpSecTunnelInterface This change corrects a bug where IpSecTunnelInterface was not removing old addresses, and resulted in EEXIST when trying to re-add an address to a given interface. Test: atest FrameworksVcnTests Change-Id: I43434c801354483a7c7d0092891799bf86da23eb --- .../server/vcn/VcnGatewayConnection.java | 16 ++--- ...cnGatewayConnectionConnectedStateTest.java | 67 +++++++++++++++++-- .../vcn/VcnGatewayConnectionTestBase.java | 8 ++- 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index eed2006382..efe7837757 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1518,13 +1518,6 @@ public class VcnGatewayConnection extends StateMachine { } } - protected void setupInterface( - int token, - @NonNull IpSecTunnelInterface tunnelIface, - @NonNull VcnChildSessionConfiguration childConfig) { - setupInterface(token, tunnelIface, childConfig, null); - } - protected void setupInterface( int token, @NonNull IpSecTunnelInterface tunnelIface, @@ -1609,9 +1602,11 @@ public class VcnGatewayConnection extends StateMachine { transformCreatedInfo.direction); break; case EVENT_SETUP_COMPLETED: + final VcnChildSessionConfiguration oldChildConfig = mChildConfig; mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig; - setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); + setupInterfaceAndNetworkAgent( + mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig); break; case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); @@ -1655,8 +1650,9 @@ public class VcnGatewayConnection extends StateMachine { protected void setupInterfaceAndNetworkAgent( int token, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull VcnChildSessionConfiguration childConfig) { - setupInterface(token, tunnelIface, childConfig); + @NonNull VcnChildSessionConfiguration childConfig, + @NonNull VcnChildSessionConfiguration oldChildConfig) { + setupInterface(token, tunnelIface, childConfig, oldChildConfig); if (mNetworkAgent == null) { mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 3b0be301ed..54086c2a33 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.net.ConnectivityManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; @@ -60,8 +61,11 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.IOException; +import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.function.Consumer; /** Tests for VcnGatewayConnection.ConnectedState */ @@ -169,12 +173,14 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } private void triggerChildOpened() { + triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR); + } + + private void triggerChildOpened(List internalAddresses, InetAddress dnsAddress) { final VcnChildSessionConfiguration mMockChildSessionConfig = mock(VcnChildSessionConfiguration.class); - doReturn(Collections.singletonList(TEST_INTERNAL_ADDR)) - .when(mMockChildSessionConfig) - .getInternalAddresses(); - doReturn(Collections.singletonList(TEST_DNS_ADDR)) + doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses(); + doReturn(Collections.singletonList(dnsAddress)) .when(mMockChildSessionConfig) .getInternalDnsServers(); @@ -248,6 +254,59 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } + @Test + public void testInternalAndDnsAddressesChanged() throws Exception { + final List startingInternalAddrs = + Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2}); + triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR); + mTestLooper.dispatchAll(); + + for (LinkAddress addr : startingInternalAddrs) { + verify(mIpSecSvc) + .addAddressToTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any()); + } + + verify(mDeps) + .newNetworkAgent( + any(), + any(), + any(), + argThat( + lp -> + startingInternalAddrs.equals(lp.getLinkAddresses()) + && Collections.singletonList(TEST_DNS_ADDR) + .equals(lp.getDnsServers())), + anyInt(), + any(), + any(), + any(), + any()); + + // Trigger another connection event, and verify that the addresses change + final List newInternalAddrs = + Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3}); + triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2); + mTestLooper.dispatchAll(); + + // Verify addresses on tunnel network added/removed + for (LinkAddress addr : newInternalAddrs) { + verify(mIpSecSvc) + .addAddressToTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any()); + } + verify(mIpSecSvc) + .removeAddressFromTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any()); + + // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties + // is mockable + + // Verify that IpSecTunnelInterface only created once + verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); + verifyNoMoreInteractions(mIpSecSvc); + } + @Test public void testSuccessfulConnectionExitsSafeMode() throws Exception { verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 884b2338d8..c5ed8f6ddc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -74,8 +74,14 @@ public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); + protected static final InetAddress TEST_DNS_ADDR_2 = + InetAddresses.parseNumericAddress("2001:DB8:0:2::"); protected static final LinkAddress TEST_INTERNAL_ADDR = - new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64); + new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64); + protected static final LinkAddress TEST_INTERNAL_ADDR_2 = + new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64); + protected static final LinkAddress TEST_INTERNAL_ADDR_3 = + new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64); protected static final int TEST_IPSEC_SPI_VALUE = 0x1234; protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1; From d145f872fafacadfd9d843c8e86f1c225ebd7bee Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 5 Apr 2021 15:01:13 -0700 Subject: [PATCH 0163/1057] Don't process dup unwanted() when unregistering NetworkAgent In cases where the NetworkAgent is unregistered (eg. Safe mode), but the VCN is not shut down, the NetworkAgent.unwanted() call should not trigger a teardown. Test: atest FrameworksVcnTests Change-Id: Icf32cb464bce2aae2846448d5a6a53a97f558398 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 8 +++++++- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index efe7837757..20c08eb2ce 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1474,7 +1474,13 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.getVcnNetworkProvider(), () -> { Slog.d(TAG, "NetworkAgent was unwanted"); - teardownAsynchronously(); + // If network agent has already been torn down, skip sending the + // disconnect. Unwanted() is always called, even when networkAgents + // are unregistered in teardownNetwork(), so prevent duplicate + // notifications. + if (mNetworkAgent != null) { + teardownAsynchronously(); + } } /* networkUnwantedCallback */, (status) -> { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 54086c2a33..34c00182f8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -312,6 +312,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( mGatewayConnection.mConnectedState); + assertTrue(mGatewayConnection.isInSafeMode()); + assertFalse(mGatewayConnection.isQuitting()); + triggerChildOpened(); mTestLooper.dispatchAll(); From 487b30ffd772115b653f0528b194a5f3877fe6e0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Apr 2021 14:11:31 -0700 Subject: [PATCH 0164/1057] Add dump to VcnManagementService This change adds basic dump functionality for debugging purposes to the VcnManagementService Test: atest FrameworksVcnTests Change-Id: Id9494f69450ffff57945701255181052f52bbb37 --- .../android/server/VcnManagementService.java | 31 ++++++++++++++ .../src/com/android/server/vcn/Vcn.java | 23 +++++++++++ .../server/vcn/VcnGatewayConnection.java | 22 ++++++++++ .../server/vcn/VcnNetworkProvider.java | 41 +++++++++++++++++++ 4 files changed, 117 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f7ae58ca0e..fc1162e1b5 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.DUMP; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; @@ -69,6 +70,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.LocationPermissionChecker; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; @@ -76,7 +78,9 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; +import java.io.FileDescriptor; import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -929,6 +933,33 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + /** + * Dumps the state of the VcnManagementService for logging and debugging purposes. + * + *

      PII and credentials MUST NEVER be dumped here. + */ + @Override + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mContext.enforceCallingOrSelfPermission(DUMP, TAG); + + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + + pw.println("VcnManagementService dump:"); + pw.increaseIndent(); + + mNetworkProvider.dump(pw); + + synchronized (mLock) { + pw.println("mVcns:"); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.println(); + } + + pw.decreaseIndent(); + } + // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService /** Callback for Vcn signals sent up to VcnManagementService. */ public interface VcnCallback { diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index ae806aa500..7bc6056f91 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -38,6 +38,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -328,6 +329,8 @@ public class Vcn extends Handler { private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { + Slog.v(getLogTag(), "Received request " + request); + if (score > getNetworkScore()) { if (VDBG) { Slog.v( @@ -409,6 +412,26 @@ public class Vcn extends Handler { return TAG + " [" + mSubscriptionGroup.hashCode() + "]"; } + /** + * Dumps the state of this Vcn for logging and debugging purposes. + * + *

      PII and credentials MUST NEVER be dumped here. + */ + public void dump(IndentingPrintWriter pw) { + pw.println("Vcn (" + mSubscriptionGroup + "):"); + pw.increaseIndent(); + + pw.println("mCurrentStatus: " + mCurrentStatus); + + pw.println("mVcnGatewayConnections:"); + for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { + gw.dump(pw); + } + pw.println(); + + pw.decreaseIndent(); + } + /** Retrieves the network score for a VCN Network */ // Package visibility for use in VcnGatewayConnection static int getNetworkScore() { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 20c08eb2ce..4f1989019c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -77,6 +77,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; @@ -1924,6 +1925,27 @@ public class VcnGatewayConnection extends StateMachine { } } + /** + * Dumps the state of this VcnGatewayConnection for logging and debugging purposes. + * + *

      PII and credentials MUST NEVER be dumped here. + */ + public void dump(IndentingPrintWriter pw) { + pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):"); + pw.increaseIndent(); + + pw.println("Current state: " + getCurrentState().getClass().getSimpleName()); + pw.println("mIsQuitting: " + mIsQuitting); + pw.println("mIsInSafeMode: " + mIsInSafeMode); + pw.println("mCurrentToken: " + mCurrentToken); + pw.println("mFailedAttempts: " + mFailedAttempts); + pw.println( + "mNetworkAgent.getNetwork(): " + + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + + pw.decreaseIndent(); + } + @VisibleForTesting(visibility = Visibility.PRIVATE) void setTunnelInterface(IpSecTunnelInterface tunnelIface) { mTunnelIface = tunnelIface; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index a909695991..be0deb57ee 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -29,6 +29,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import java.util.Objects; import java.util.Set; @@ -129,10 +130,50 @@ public class VcnNetworkProvider extends NetworkProvider { mScore = score; mProviderId = providerId; } + + /** + * Dumps the state of this NetworkRequestEntry for logging and debugging purposes. + * + *

      PII and credentials MUST NEVER be dumped here. + */ + public void dump(IndentingPrintWriter pw) { + pw.println("NetworkRequestEntry:"); + pw.increaseIndent(); + + pw.println("mRequest: " + mRequest); + pw.println("mScore: " + mScore); + pw.println("mProviderId: " + mProviderId); + + pw.decreaseIndent(); + } } // package-private interface NetworkRequestListener { void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId); } + + /** + * Dumps the state of this VcnNetworkProvider for logging and debugging purposes. + * + *

      PII and credentials MUST NEVER be dumped here. + */ + public void dump(IndentingPrintWriter pw) { + pw.println("VcnNetworkProvider:"); + pw.increaseIndent(); + + pw.println("mListeners:"); + for (NetworkRequestListener listener : mListeners) { + pw.println(listener); + } + pw.println(); + + pw.println("mRequests.values:"); + for (NetworkRequestEntry entry : mRequests.values()) { + entry.dump(pw); + } + pw.println(); + + pw.decreaseIndent(); + } } From 30b706bb0a29241a33f0d3a7fd5ffd0fae718639 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 5 Apr 2021 18:11:20 -0700 Subject: [PATCH 0165/1057] Ensure teardown() only triggered on the right NetworkAgent. This change ensures that teardown() is only ever triggered when the NetworkAgent matches the one that the unwanted() callback is triggered on. This ensures that in cases where the unwanted() is called as a result of unregister(), or even after a new NetworkAgent is created (and stored in the mNetworkAgent field), the teardown does not occur. Bug: 184304972 Test: atest FrameworksVcnTests Change-Id: Ic8ab66ff1e48d43be784974cda7574d0191e557f --- .../server/vcn/VcnGatewayConnection.java | 26 ++++---- ...cnGatewayConnectionConnectedStateTest.java | 60 +++++++++++++++++++ 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 4f1989019c..ddf8b46181 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1473,15 +1473,21 @@ public class VcnGatewayConnection extends StateMachine { Vcn.getNetworkScore(), nac, mVcnContext.getVcnNetworkProvider(), - () -> { - Slog.d(TAG, "NetworkAgent was unwanted"); - // If network agent has already been torn down, skip sending the - // disconnect. Unwanted() is always called, even when networkAgents - // are unregistered in teardownNetwork(), so prevent duplicate - // notifications. - if (mNetworkAgent != null) { - teardownAsynchronously(); + (agentRef) -> { + // Only trigger teardown if the NetworkAgent hasn't been replaced or + // changed. This guards against two cases - the first where + // unwanted() may be called as a result of the + // NetworkAgent.unregister() call, which might trigger a teardown + // instead of just a Network disconnect, as well as the case where a + // new NetworkAgent replaces an old one before the unwanted() call + // is processed. + if (mNetworkAgent != agentRef) { + Slog.d(TAG, "unwanted() called on stale NetworkAgent"); + return; } + + Slog.d(TAG, "NetworkAgent was unwanted"); + teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { @@ -2089,7 +2095,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull int score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, - @NonNull Runnable networkUnwantedCallback, + @NonNull Consumer networkUnwantedCallback, @NonNull Consumer validationStatusCallback) { return new NetworkAgent( vcnContext.getContext(), @@ -2102,7 +2108,7 @@ public class VcnGatewayConnection extends StateMachine { provider) { @Override public void onNetworkUnwanted() { - networkUnwantedCallback.run(); + networkUnwantedCallback.accept(this); } @Override diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 34c00182f8..5dcf4a8621 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -323,6 +323,66 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } + private Consumer setupNetworkAndGetUnwantedCallback() { + triggerChildOpened(); + mTestLooper.dispatchAll(); + + final ArgumentCaptor> unwantedCallbackCaptor = + ArgumentCaptor.forClass(Consumer.class); + verify(mDeps) + .newNetworkAgent( + any(), + any(), + any(), + any(), + anyInt(), + any(), + any(), + unwantedCallbackCaptor.capture(), + any()); + + return unwantedCallbackCaptor.getValue(); + } + + @Test + public void testUnwantedNetworkAgentTriggersTeardown() throws Exception { + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + + unwantedCallback.accept(mNetworkAgent); + mTestLooper.dispatchAll(); + + assertTrue(mGatewayConnection.isQuitting()); + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception { + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + + mGatewayConnection.setNetworkAgent(null); + unwantedCallback.accept(mNetworkAgent); + mTestLooper.dispatchAll(); + + // Verify that the call was ignored; the state machine is still running, and the state has + // not changed. + assertFalse(mGatewayConnection.isQuitting()); + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception { + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + final NetworkAgent testAgent = mock(NetworkAgent.class); + + mGatewayConnection.setNetworkAgent(testAgent); + unwantedCallback.accept(mNetworkAgent); + mTestLooper.dispatchAll(); + + assertFalse(mGatewayConnection.isQuitting()); + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + assertEquals(testAgent, mGatewayConnection.getNetworkAgent()); + } + @Test public void testChildSessionClosedTriggersDisconnect() throws Exception { // Verify scheduled but not canceled when entering ConnectedState From 1269915209cfec27fed06a8ce8452ec2f833f3b0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 6 Apr 2021 18:08:13 -0700 Subject: [PATCH 0166/1057] Create proxy NetworkAgent for testing This change adds a proxy NetworkAgent to facilitate testing, adding the ability to test final methods such as sendNetworkCapabilities() and sendLinkProperties(), which would otherwise call a real implementation, and throw a null pointer while trying to access internal fields. Bug: 184579891 Bug: 184697651 Test: atest FrameworksVcnTests Change-Id: I8f13159bd266bf488f095a13d6ffe444bec65f38 --- .../server/vcn/VcnGatewayConnection.java | 106 ++++++++++++++---- ...cnGatewayConnectionConnectedStateTest.java | 22 ++-- .../vcn/VcnGatewayConnectionTestBase.java | 6 +- 3 files changed, 98 insertions(+), 36 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index ddf8b46181..8d24c3ab0c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -575,7 +575,7 @@ public class VcnGatewayConnection extends StateMachine { *

      Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable * otherwise. */ - private NetworkAgent mNetworkAgent; + private VcnNetworkAgent mNetworkAgent; @Nullable private WakeupMessage mTeardownTimeoutAlarm; @Nullable private WakeupMessage mDisconnectRequestAlarm; @@ -1441,7 +1441,7 @@ public class VcnGatewayConnection extends StateMachine { private abstract class ConnectedStateBase extends ActiveBaseState { protected void updateNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, - @NonNull NetworkAgent agent, + @NonNull VcnNetworkAgent agent, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying); @@ -1452,7 +1452,7 @@ public class VcnGatewayConnection extends StateMachine { agent.sendLinkProperties(lp); } - protected NetworkAgent buildNetworkAgent( + protected VcnNetworkAgent buildNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = @@ -1464,7 +1464,7 @@ public class VcnGatewayConnection extends StateMachine { .setLegacyType(ConnectivityManager.TYPE_MOBILE) .build(); - final NetworkAgent agent = + final VcnNetworkAgent agent = mDeps.newNetworkAgent( mVcnContext, TAG, @@ -1993,12 +1993,12 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - NetworkAgent getNetworkAgent() { + VcnNetworkAgent getNetworkAgent() { return mNetworkAgent; } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setNetworkAgent(@Nullable NetworkAgent networkAgent) { + void setNetworkAgent(@Nullable VcnNetworkAgent networkAgent) { mNetworkAgent = networkAgent; } @@ -2086,8 +2086,8 @@ public class VcnGatewayConnection extends StateMachine { return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable); } - /** Builds a new NetworkAgent. */ - public NetworkAgent newNetworkAgent( + /** Builds a new VcnNetworkAgent. */ + public VcnNetworkAgent newNetworkAgent( @NonNull VcnContext vcnContext, @NonNull String tag, @NonNull NetworkCapabilities caps, @@ -2095,27 +2095,18 @@ public class VcnGatewayConnection extends StateMachine { @NonNull int score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, - @NonNull Consumer networkUnwantedCallback, + @NonNull Consumer networkUnwantedCallback, @NonNull Consumer validationStatusCallback) { - return new NetworkAgent( - vcnContext.getContext(), - vcnContext.getLooper(), + return new VcnNetworkAgent( + vcnContext, tag, caps, lp, score, nac, - provider) { - @Override - public void onNetworkUnwanted() { - networkUnwantedCallback.accept(this); - } - - @Override - public void onValidationStatus(int status, @Nullable Uri redirectUri) { - validationStatusCallback.accept(status); - } - }; + provider, + networkUnwantedCallback, + validationStatusCallback); } /** Gets the elapsed real time since boot, in millis. */ @@ -2231,4 +2222,73 @@ public class VcnGatewayConnection extends StateMachine { mImpl.release(); } } + + /** Proxy Implementation of NetworkAgent, used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnNetworkAgent { + private final NetworkAgent mImpl; + + public VcnNetworkAgent( + @NonNull VcnContext vcnContext, + @NonNull String tag, + @NonNull NetworkCapabilities caps, + @NonNull LinkProperties lp, + @NonNull int score, + @NonNull NetworkAgentConfig nac, + @NonNull NetworkProvider provider, + @NonNull Consumer networkUnwantedCallback, + @NonNull Consumer validationStatusCallback) { + mImpl = + new NetworkAgent( + vcnContext.getContext(), + vcnContext.getLooper(), + tag, + caps, + lp, + score, + nac, + provider) { + @Override + public void onNetworkUnwanted() { + networkUnwantedCallback.accept(VcnNetworkAgent.this); + } + + @Override + public void onValidationStatus(int status, @Nullable Uri redirectUri) { + validationStatusCallback.accept(status); + } + }; + } + + /** Registers the underlying NetworkAgent */ + public void register() { + mImpl.register(); + } + + /** Marks the underlying NetworkAgent as connected */ + public void markConnected() { + mImpl.markConnected(); + } + + /** Unregisters the underlying NetworkAgent */ + public void unregister() { + mImpl.unregister(); + } + + /** Sends new NetworkCapabilities for the underlying NetworkAgent */ + public void sendNetworkCapabilities(@NonNull NetworkCapabilities caps) { + mImpl.sendNetworkCapabilities(caps); + } + + /** Sends new LinkProperties for the underlying NetworkAgent */ + public void sendLinkProperties(@NonNull LinkProperties lp) { + mImpl.sendLinkProperties(lp); + } + + /** Retrieves the Network for the underlying NetworkAgent */ + @Nullable + public Network getNetwork() { + return mImpl.getNetwork(); + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 5dcf4a8621..cb7c96a273 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -26,6 +26,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -73,13 +74,13 @@ import java.util.function.Consumer; @SmallTest public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { private VcnIkeSession mIkeSession; - private NetworkAgent mNetworkAgent; + private VcnNetworkAgent mNetworkAgent; @Before public void setUp() throws Exception { super.setUp(); - mNetworkAgent = mock(NetworkAgent.class); + mNetworkAgent = mock(VcnNetworkAgent.class); doReturn(mNetworkAgent) .when(mDeps) .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any()); @@ -299,8 +300,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .removeAddressFromTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any()); - // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties - // is mockable + verify(mNetworkAgent).sendLinkProperties(argThat( + lp -> newInternalAddrs.equals(lp.getLinkAddresses()) + && Collections.singletonList(TEST_DNS_ADDR_2).equals(lp.getDnsServers()))); // Verify that IpSecTunnelInterface only created once verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); @@ -323,11 +325,11 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } - private Consumer setupNetworkAndGetUnwantedCallback() { + private Consumer setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); - final ArgumentCaptor> unwantedCallbackCaptor = + final ArgumentCaptor> unwantedCallbackCaptor = ArgumentCaptor.forClass(Consumer.class); verify(mDeps) .newNetworkAgent( @@ -346,7 +348,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testUnwantedNetworkAgentTriggersTeardown() throws Exception { - final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); unwantedCallback.accept(mNetworkAgent); mTestLooper.dispatchAll(); @@ -357,7 +359,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception { - final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); mGatewayConnection.setNetworkAgent(null); unwantedCallback.accept(mNetworkAgent); @@ -371,8 +373,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception { - final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); - final NetworkAgent testAgent = mock(NetworkAgent.class); + final Consumer unwantedCallback = setupNetworkAndGetUnwantedCallback(); + final VcnNetworkAgent testAgent = mock(VcnNetworkAgent.class); mGatewayConnection.setNetworkAgent(testAgent); unwantedCallback.accept(mNetworkAgent); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index c5ed8f6ddc..b93347bbd9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -18,6 +18,7 @@ package com.android.server.vcn; import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.junit.Assert.assertEquals; @@ -44,7 +45,6 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; -import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; @@ -278,8 +278,8 @@ public class VcnGatewayConnectionTestBase { protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( @NonNull State expectedState) { - // Set a NetworkAgent, and expect it to be unregistered and cleared - final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class); + // Set a VcnNetworkAgent, and expect it to be unregistered and cleared + final VcnNetworkAgent mockNetworkAgent = mock(VcnNetworkAgent.class); mGatewayConnection.setNetworkAgent(mockNetworkAgent); // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial From 84d1d6b558cd98408c45ef774387937584a07dab Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 7 Apr 2021 15:11:49 -0700 Subject: [PATCH 0167/1057] Remove location-permission check from VcnStatusCallbacks. This CL updates VcnManagementService to not require location permissions for receiving VcnStatusCallback invocations. This change is safe to make because these callbacks are not capable of leaking any location-related information. Bug: 180556279 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I38600aeb2489f139b3479b07de77facc2ae838c5 --- .../android/server/VcnManagementService.java | 11 ---- .../server/VcnManagementServiceTest.java | 50 ++----------------- 2 files changed, 3 insertions(+), 58 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f7ae58ca0e..8796516c10 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -168,9 +168,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback(); - /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */ - @Nullable private LocationPermissionChecker mLocationPermissionChecker; - @GuardedBy("mLock") @NonNull private final Map mConfigs = new ArrayMap<>(); @@ -369,7 +366,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { new NetworkRequest.Builder().clearCapabilities().build(), mTrackingNetworkCallback); mTelephonySubscriptionTracker.register(); - mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext()); } private void enforcePrimaryUser() { @@ -836,13 +832,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { return false; } - if (!mLocationPermissionChecker.checkLocationPermission( - cbInfo.mPkgName, - "VcnStatusCallback" /* featureId */, - cbInfo.mUid, - null /* message */)) { - return false; - } return true; } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 43e6676e1d..bbc9bb600f 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -81,7 +81,6 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.LocationPermissionChecker; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnStatusCallbackInfo; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -162,8 +161,6 @@ public class VcnManagementServiceTest { mock(PersistableBundleUtils.LockingReadWriteHelper.class); private final TelephonySubscriptionTracker mSubscriptionTracker = mock(TelephonySubscriptionTracker.class); - private final LocationPermissionChecker mLocationPermissionChecker = - mock(LocationPermissionChecker.class); private final ArgumentCaptor mVcnCallbackCaptor = ArgumentCaptor.forClass(VcnCallback.class); @@ -207,9 +204,6 @@ public class VcnManagementServiceTest { doReturn(mConfigReadWriteHelper) .when(mMockDeps) .newPersistableBundleLockingReadWriteHelper(any()); - doReturn(mLocationPermissionChecker) - .when(mMockDeps) - .newLocationPermissionChecker(eq(mMockContext)); // Setup VCN instance generation doAnswer((invocation) -> { @@ -521,10 +515,6 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { - mVcnMgmtSvc.systemReady(); - doReturn(true) - .when(mLocationPermissionChecker) - .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); @@ -697,10 +687,6 @@ public class VcnManagementServiceTest { doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE) .when(vcn) .getStatus(); - - doReturn(true) - .when(mLocationPermissionChecker) - .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); } private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport( @@ -933,8 +919,7 @@ public class VcnManagementServiceTest { @NonNull ParcelUuid subGroup, @NonNull String pkgName, int uid, - boolean hasPermissionsforSubGroup, - boolean hasLocationPermission) + boolean hasPermissionsforSubGroup) throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); @@ -946,10 +931,6 @@ public class VcnManagementServiceTest { .when(snapshot) .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName)); - doReturn(hasLocationPermission) - .when(mLocationPermissionChecker) - .checkLocationPermission(eq(pkgName), any(), eq(uid), any()); - mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */); @@ -959,11 +940,7 @@ public class VcnManagementServiceTest { public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges() throws Exception { triggerVcnStatusCallbackOnSafeModeStatusChanged( - TEST_UUID_1, - TEST_PACKAGE_NAME, - TEST_UID, - true /* hasPermissionsforSubGroup */, - true /* hasLocationPermission */); + TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, true /* hasPermissionsforSubGroup */); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @@ -972,25 +949,7 @@ public class VcnManagementServiceTest { public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges() throws Exception { triggerVcnStatusCallbackOnSafeModeStatusChanged( - TEST_UUID_1, - TEST_PACKAGE_NAME, - TEST_UID, - false /* hasPermissionsforSubGroup */, - true /* hasLocationPermission */); - - verify(mMockStatusCallback, never()) - .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); - } - - @Test - public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission() - throws Exception { - triggerVcnStatusCallbackOnSafeModeStatusChanged( - TEST_UUID_1, - TEST_PACKAGE_NAME, - TEST_UID, - true /* hasPermissionsforSubGroup */, - false /* hasLocationPermission */); + TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, false /* hasPermissionsforSubGroup */); verify(mMockStatusCallback, never()) .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); @@ -1052,9 +1011,6 @@ public class VcnManagementServiceTest { .when(snapshot) .packageHasPermissionsForSubscriptionGroup( eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME)); - doReturn(true) - .when(mLocationPermissionChecker) - .checkLocationPermission(eq(TEST_CB_PACKAGE_NAME), any(), eq(TEST_UID), any()); mVcnMgmtSvc.registerVcnStatusCallback( TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME); From c4e47b04e2bb4794cf9ed378d5d44154b25788b9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 6 Apr 2021 18:08:43 -0700 Subject: [PATCH 0168/1057] Dynamically set MTU based on proposed algorithms This change adds the relevant utilities and plumbing to ensure that MTUs are set dynamically based on the underlying network's MTU. Bug: 184697651 Test: atest FrameworksVcnTests Change-Id: I77e34a92eb4e81e83d20fe6019b38ea5f1af4765 --- .../src/android/net/vcn/util/MtuUtils.java | 155 ++++++++++++++++++ .../server/vcn/VcnGatewayConnection.java | 96 ++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 19 ++- .../vcn/VcnGatewayConnectionTestBase.java | 10 ++ .../android/server/vcn/util/MtuUtilsTest.java | 92 +++++++++++ 5 files changed, 364 insertions(+), 8 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java new file mode 100644 index 0000000000..49c1a02215 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java @@ -0,0 +1,155 @@ +/* + * 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.server.vcn.util; + +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_CTR; +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.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96; +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 com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; + +import static java.lang.Math.max; +import static java.util.Collections.unmodifiableMap; + +import android.annotation.NonNull; +import android.net.ipsec.ike.ChildSaProposal; +import android.util.ArrayMap; +import android.util.Pair; +import android.util.Slog; + +import java.util.List; +import java.util.Map; + +/** @hide */ +public class MtuUtils { + private static final String TAG = MtuUtils.class.getSimpleName(); + /** + * Max ESP overhead possible + * + *

      60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader) + */ + private static final int GENERIC_ESP_OVERHEAD_MAX = 78; + + /** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */ + private static final Map AUTH_ALGORITHM_OVERHEAD; + + static { + final Map map = new ArrayMap<>(); + map.put(INTEGRITY_ALGORITHM_NONE, 0); + map.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, 12); + map.put(INTEGRITY_ALGORITHM_AES_XCBC_96, 12); + map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 32); + map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 48); + map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, 64); + map.put(INTEGRITY_ALGORITHM_AES_CMAC_96, 12); + + AUTH_ALGORITHM_OVERHEAD = unmodifiableMap(map); + } + + /** Maximum overheads of encryption algorithms, keyed on IANA-defined constants */ + private static final Map CRYPT_ALGORITHM_OVERHEAD; + + static { + final Map map = new ArrayMap<>(); + map.put(ENCRYPTION_ALGORITHM_3DES, 15); // 8 (IV) + 7 (Max pad) + map.put(ENCRYPTION_ALGORITHM_AES_CBC, 31); // 16 (IV) + 15 (Max pad) + map.put(ENCRYPTION_ALGORITHM_AES_CTR, 11); // 8 (IV) + 3 (Max pad) + + CRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map); + } + + /** Maximum overheads of combined mode algorithms, keyed on IANA-defined constants */ + private static final Map AUTHCRYPT_ALGORITHM_OVERHEAD; + + static { + final Map map = new ArrayMap<>(); + map.put(ENCRYPTION_ALGORITHM_AES_GCM_8, 19); // 8 (IV) + 3 (Max pad) + 8 (ICV) + map.put(ENCRYPTION_ALGORITHM_AES_GCM_12, 23); // 8 (IV) + 3 (Max pad) + 12 (ICV) + map.put(ENCRYPTION_ALGORITHM_AES_GCM_16, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV) + map.put(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV) + + AUTHCRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map); + } + + /** + * Calculates the MTU of the inner interface based on the parameters provided + * + *

      The MTU of the inner interface will be the minimum of the following: + * + *

        + *
      • The MTU of the outer interface, minus the greatest ESP overhead (based on proposed + * algorithms). + *
      • The maximum MTU as provided in the arguments. + *
      + */ + public static int getMtu( + @NonNull List childProposals, int maxMtu, int underlyingMtu) { + if (underlyingMtu <= 0) { + return IPV6_MIN_MTU; + } + + boolean hasUnknownAlgorithm = false; + int maxAuthOverhead = 0; + int maxCryptOverhead = 0; + int maxAuthCryptOverhead = 0; + + for (ChildSaProposal proposal : childProposals) { + for (Pair encryptionAlgoPair : proposal.getEncryptionAlgorithms()) { + final int algo = encryptionAlgoPair.first; + + if (AUTHCRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) { + maxAuthCryptOverhead = + max(maxAuthCryptOverhead, AUTHCRYPT_ALGORITHM_OVERHEAD.get(algo)); + continue; + } else if (CRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) { + maxCryptOverhead = max(maxCryptOverhead, CRYPT_ALGORITHM_OVERHEAD.get(algo)); + continue; + } + + Slog.wtf(TAG, "Unknown encryption algorithm requested: " + algo); + return IPV6_MIN_MTU; + } + + for (int algo : proposal.getIntegrityAlgorithms()) { + if (AUTH_ALGORITHM_OVERHEAD.containsKey(algo)) { + maxAuthOverhead = max(maxAuthOverhead, AUTH_ALGORITHM_OVERHEAD.get(algo)); + continue; + } + + Slog.wtf(TAG, "Unknown integrity algorithm requested: " + algo); + return IPV6_MIN_MTU; + } + } + + // Return minimum of maxMtu, and the adjusted MTUs based on algorithms. + final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX; + final int normalModeMtu = + underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX; + return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8d24c3ab0c..83ac36f9e0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -85,6 +85,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.util.MtuUtils; import java.io.IOException; import java.net.Inet4Address; @@ -449,6 +450,44 @@ public class VcnGatewayConnection extends StateMachine { */ private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10; + /** + * Sent when an IKE has completed migration, and created updated transforms for application. + * + *

      Only relevant in the Connected state. + * + * @param arg1 The session token for the IKE Session that completed migration, used to prevent + * out-of-date signals from propagating. + * @param obj @NonNull An EventMigrationCompletedInfo instance with relevant data. + */ + private static final int EVENT_MIGRATION_COMPLETED = 11; + + private static class EventMigrationCompletedInfo implements EventInfo { + @NonNull public final IpSecTransform inTransform; + @NonNull public final IpSecTransform outTransform; + + EventMigrationCompletedInfo( + @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) { + this.inTransform = Objects.requireNonNull(inTransform); + this.outTransform = Objects.requireNonNull(outTransform); + } + + @Override + public int hashCode() { + return Objects.hash(inTransform, outTransform); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventMigrationCompletedInfo)) { + return false; + } + + final EventMigrationCompletedInfo rhs = (EventMigrationCompletedInfo) other; + return Objects.equals(inTransform, rhs.inTransform) + && Objects.equals(outTransform, rhs.outTransform); + } + } + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -1054,6 +1093,14 @@ public class VcnGatewayConnection extends StateMachine { sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token); } + private void migrationCompleted( + int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) { + sendMessageAndAcquireWakeLock( + EVENT_MIGRATION_COMPLETED, + token, + new EventMigrationCompletedInfo(inTransform, outTransform)); + } + private void childTransformCreated( int token, @NonNull IpSecTransform transform, int direction) { sendMessageAndAcquireWakeLock( @@ -1149,7 +1196,9 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SETUP_COMPLETED: // Fallthrough case EVENT_DISCONNECT_REQUESTED: // Fallthrough case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough - case EVENT_SUBSCRIPTIONS_CHANGED: + case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough + case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough + case EVENT_MIGRATION_COMPLETED: logUnexpectedEvent(msg.what); break; default: @@ -1446,7 +1495,8 @@ public class VcnGatewayConnection extends StateMachine { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying); final LinkProperties lp = - buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); + buildConnectedLinkProperties( + mConnectionConfig, tunnelIface, childConfig, mUnderlying); agent.sendNetworkCapabilities(caps); agent.sendLinkProperties(lp); @@ -1458,7 +1508,8 @@ public class VcnGatewayConnection extends StateMachine { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying); final LinkProperties lp = - buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); + buildConnectedLinkProperties( + mConnectionConfig, tunnelIface, childConfig, mUnderlying); final NetworkAgentConfig nac = new NetworkAgentConfig.Builder() .setLegacyType(ConnectivityManager.TYPE_MOBILE) @@ -1627,12 +1678,36 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: handleSafeModeTimeoutExceeded(); break; + case EVENT_MIGRATION_COMPLETED: + final EventMigrationCompletedInfo migrationCompletedInfo = + (EventMigrationCompletedInfo) msg.obj; + + handleMigrationCompleted(migrationCompletedInfo); + break; default: logUnhandledMessage(msg); break; } } + private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) { + applyTransform( + mCurrentToken, + mTunnelIface, + mUnderlying.network, + migrationCompletedInfo.inTransform, + IpSecManager.DIRECTION_IN); + + applyTransform( + mCurrentToken, + mTunnelIface, + mUnderlying.network, + migrationCompletedInfo.outTransform, + IpSecManager.DIRECTION_OUT); + + updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + } + private void handleUnderlyingNetworkChanged(@NonNull Message msg) { final UnderlyingNetworkRecord oldUnderlying = mUnderlying; mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; @@ -1822,7 +1897,10 @@ public class VcnGatewayConnection extends StateMachine { private static LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, - @NonNull VcnChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @Nullable UnderlyingNetworkRecord underlying) { + final VcnControlPlaneIkeConfig controlPlaneConfig = + (VcnControlPlaneIkeConfig) gatewayConnectionConfig.getControlPlaneConfig(); final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -1838,7 +1916,12 @@ public class VcnGatewayConnection extends StateMachine { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, null /*iface*/, RouteInfo.RTN_UNICAST)); - lp.setMtu(gatewayConnectionConfig.getMaxMtu()); + final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu(); + lp.setMtu( + MtuUtils.getMtu( + controlPlaneConfig.getChildSessionParams().getSaProposals(), + gatewayConnectionConfig.getMaxMtu(), + underlyingMtu)); return lp; } @@ -1919,8 +2002,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform outIpSecTransform) { Slog.v(TAG, "ChildTransformsMigrated; token " + mToken); - onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN); - onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT); + migrationCompleted(mToken, inIpSecTransform, outIpSecTransform); } @Override diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index cb7c96a273..bb67593d84 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -47,15 +47,19 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; +import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.TemporaryFailureException; +import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnManager.VcnErrorCode; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.util.MtuUtils; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -153,7 +157,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } @Test - public void testMigratedTransformsAreApplied() throws Exception { + public void testMigration() throws Exception { + triggerChildOpened(); + getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); @@ -171,6 +177,17 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + + final List saProposals = + ((VcnControlPlaneIkeConfig) mConfig.getControlPlaneConfig()) + .getChildSessionParams() + .getSaProposals(); + final int expectedMtu = + MtuUtils.getMtu( + saProposals, + mConfig.getMaxMtu(), + TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu()); + verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu())); } private void triggerChildOpened() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index b93347bbd9..dc73be25ff 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -90,12 +90,18 @@ public class VcnGatewayConnectionTestBase { protected static final int TEST_SUB_ID = 5; protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( new Network(0), new NetworkCapabilities(), new LinkProperties(), false /* blocked */); + + static { + TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500); + } + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = new UnderlyingNetworkRecord( new Network(1), @@ -103,6 +109,10 @@ public class VcnGatewayConnectionTestBase { new LinkProperties(), false /* blocked */); + static { + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460); + } + protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java new file mode 100644 index 0000000000..29511f780b --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.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.server.vcn.util; + +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_HMAC_SHA2_256_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; + +import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU; +import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; +import static com.android.server.vcn.util.MtuUtils.getMtu; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import static java.util.Collections.emptyList; + +import android.net.ipsec.ike.ChildSaProposal; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MtuUtilsTest { + @Test + public void testUnderlyingMtuZero() { + assertEquals( + IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */)); + } + + @Test + public void testClampsToMaxMtu() { + assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */)); + } + + @Test + public void testNormalModeAlgorithmLessThanUnderlyingMtu() { + final List saProposals = + Arrays.asList( + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .build()); + + final int actualMtu = + getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + assertTrue(ETHER_MTU > actualMtu); + } + + @Test + public void testCombinedModeAlgorithmLessThanUnderlyingMtu() { + final List saProposals = + Arrays.asList( + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256) + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256) + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256) + .build()); + + final int actualMtu = + getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + assertTrue(ETHER_MTU > actualMtu); + } +} From b7ee1bc682ce49aebf07a00f9b93f5ca4cd6ac49 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 6 Apr 2021 15:30:00 -0700 Subject: [PATCH 0169/1057] Replace VcnControlPlaneConfig with TunnelConnectionParams Test: atest CtsVcnTestCases Bug: 180664474 Change-Id: I2fdcafbb01a01fd5ec0a17ddd5ab2db1267d2f3f --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 107ae44134..c9797d1a3c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -37,10 +37,10 @@ import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.SaProposal; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.vcn.VcnConfig; -import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.os.ParcelUuid; @@ -123,11 +123,11 @@ public class VcnManagerTest { final TunnelModeChildSessionParams childParams = new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); - final VcnControlPlaneIkeConfig controlConfig = - new VcnControlPlaneIkeConfig(ikeParams, childParams); + final IkeTunnelConnectionParams tunnelParams = + new IkeTunnelConnectionParams(ikeParams, childParams); final VcnGatewayConnectionConfig gatewayConnConfig = - new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, controlConfig) + new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, tunnelParams) .addExposedCapability(NET_CAPABILITY_INTERNET) .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) .setRetryInterval( From 233dc521b368503fae05c07922be0acb442b2415 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 9 Apr 2021 13:13:38 -0700 Subject: [PATCH 0170/1057] Use IkeProtocolException#getErrorType() to identify a specific error AuthenticationFailedException and TemporaryFailureException will not be System APIs. This patch changes VCN to use IkeProtocolException#getErrorType to identify a specific protocol error. Test: atest FrameworksVcnTests Bug: 175091931 Change-Id: Iaf3c1c9bd34957b0efdbfd7595c2838b56449308 --- .../server/vcn/VcnGatewayConnection.java | 13 +++++++++++-- ...VcnGatewayConnectionConnectedStateTest.java | 18 ++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 83ac36f9e0..1d55ba464f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; @@ -57,7 +58,6 @@ import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -1051,12 +1051,21 @@ public class VcnGatewayConnection extends StateMachine { sessionLostWithoutCallback(token, exception); } + private static boolean isIkeAuthFailure(@NonNull Exception exception) { + if (!(exception instanceof IkeProtocolException)) { + return false; + } + + return ((IkeProtocolException) exception).getErrorType() + == ERROR_TYPE_AUTHENTICATION_FAILED; + } + private void notifyStatusCallbackForSessionClosed(@NonNull Exception exception) { final int errorCode; final String exceptionClass; final String exceptionMessage; - if (exception instanceof AuthenticationFailedException) { + if (isIkeAuthFailure(exception)) { errorCode = VCN_ERROR_CODE_CONFIG_ERROR; exceptionClass = exception.getClass().getName(); exceptionMessage = exception.getMessage(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index bb67593d84..a2223e8c1e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -20,6 +20,8 @@ import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; @@ -41,6 +43,7 @@ import static org.mockito.Mockito.never; 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.net.ConnectivityManager; import android.net.LinkAddress; @@ -48,10 +51,9 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; -import android.net.ipsec.ike.exceptions.TemporaryFailureException; +import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnManager.VcnErrorCode; @@ -470,10 +472,17 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any()); } + private static IkeProtocolException buildMockIkeProtocolException(int errorCode) { + final IkeProtocolException exception = mock(IkeProtocolException.class); + when(exception.getErrorType()).thenReturn(errorCode); + return exception; + } + @Test public void testIkeSessionClosedExceptionallyAuthenticationFailure() throws Exception { verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( - new AuthenticationFailedException("vcn test"), VCN_ERROR_CODE_CONFIG_ERROR); + buildMockIkeProtocolException(ERROR_TYPE_AUTHENTICATION_FAILED), + VCN_ERROR_CODE_CONFIG_ERROR); } @Test @@ -485,7 +494,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testIkeSessionClosedExceptionallyInternalFailure() throws Exception { verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( - new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); + buildMockIkeProtocolException(ERROR_TYPE_TEMPORARY_FAILURE), + VCN_ERROR_CODE_INTERNAL_ERROR); } @Test From 9b004adb4147fae204121891832bce6b36d887c2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 15:55:51 -0700 Subject: [PATCH 0171/1057] Remove unused variable in MtuUtils Test: atest FrameworksNetTests Change-Id: If2abfec1e5755b3f8cc17fb307ec3e1633bb3e18 --- Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java index 49c1a02215..5d40cca3e1 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java @@ -113,7 +113,6 @@ public class MtuUtils { return IPV6_MIN_MTU; } - boolean hasUnknownAlgorithm = false; int maxAuthOverhead = 0; int maxCryptOverhead = 0; int maxAuthCryptOverhead = 0; From 578d519d49d64e11c3d97aeb7f6c2c8cf18aee3f Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 13 Apr 2021 18:34:51 +0800 Subject: [PATCH 0172/1057] Remove hidden connectivity method access in FrameworksVcnTests Due to connectivity modularization work, hidden connectivity methods and members are not accessible outside the module. Remove the corresponding usage. The test case in VcnNetworkProviderTest are not able to create NetworkRequests with request id assigned. The loop to create different request is removed. After that, the test does not provide more test coverage than other tests. Thus, Remove the test case directly. Bug: 182859030 Test: atest FrameworksVcnTests Change-Id: I488f62089d1dbe93c232f892885d944bef896df6 --- .../server/VcnManagementServiceTest.java | 6 ++-- .../server/vcn/VcnGatewayConnectionTest.java | 30 +++++++++--------- .../vcn/VcnGatewayConnectionTestBase.java | 5 +-- .../server/vcn/VcnNetworkProviderTest.java | 31 ------------------- 4 files changed, 22 insertions(+), 50 deletions(-) diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index bbc9bb600f..9a663436f9 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -39,6 +39,7 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; @@ -59,7 +60,6 @@ import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkCapabilities.Transport; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnStatusCallback; @@ -657,7 +657,7 @@ public class VcnManagementServiceTest { private void verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, - @Transport int transportType, + int transportType, boolean isVcnManaged, boolean isRestricted) { assertTrue(mergedCapabilities.hasTransport(transportType)); @@ -779,7 +779,7 @@ public class VcnManagementServiceTest { .registerNetworkCallback( eq(new NetworkRequest.Builder().clearCapabilities().build()), captor.capture()); - captor.getValue().onCapabilitiesChanged(new Network(0), caps); + captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index d08af9dd33..ced8745e89 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -25,7 +25,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -83,31 +86,30 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { super.setUp(); mWifiInfo = mock(WifiInfo.class); + doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong()); } private void verifyBuildNetworkCapabilitiesCommon(int transportType) { - final NetworkCapabilities underlyingCaps = new NetworkCapabilities(); - underlyingCaps.addTransportType(transportType); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING); + final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder(); + capBuilder.addTransportType(transportType); + capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + capBuilder.addCapability(NET_CAPABILITY_NOT_METERED); + capBuilder.addCapability(NET_CAPABILITY_NOT_ROAMING); if (transportType == TRANSPORT_WIFI) { - underlyingCaps.setTransportInfo(mWifiInfo); - underlyingCaps.setOwnerUid(TEST_UID); + capBuilder.setTransportInfo(mWifiInfo); + capBuilder.setOwnerUid(TEST_UID); } else if (transportType == TRANSPORT_CELLULAR) { - underlyingCaps.setAdministratorUids(new int[] {TEST_UID}); - underlyingCaps.setNetworkSpecifier( + capBuilder.setNetworkSpecifier( new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); } - - UnderlyingNetworkRecord record = - new UnderlyingNetworkRecord( - new Network(0), underlyingCaps, new LinkProperties(), false); + capBuilder.setAdministratorUids(new int[] {TEST_UID}); + UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( VcnGatewayConnectionConfigTest.buildTestConfig(), record); - assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index dc73be25ff..98d553dab0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -93,7 +94,7 @@ public class VcnGatewayConnectionTestBase { protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( - new Network(0), + mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), false /* blocked */); @@ -104,7 +105,7 @@ public class VcnGatewayConnectionTestBase { protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = new UnderlyingNetworkRecord( - new Network(1), + mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), false /* blocked */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index c2c6200fd5..f943f34c9d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -22,8 +22,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.test.TestLooper; @@ -36,9 +34,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.ArrayList; -import java.util.List; - /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @SmallTest @@ -46,8 +41,6 @@ public class VcnNetworkProviderTest { private static final int TEST_SCORE_UNSATISFIED = 0; private static final int TEST_SCORE_HIGH = 100; private static final int TEST_PROVIDER_ID = 1; - private static final int TEST_LEGACY_TYPE = ConnectivityManager.TYPE_MOBILE; - private static final NetworkRequest.Type TEST_REQUEST_TYPE = NetworkRequest.Type.REQUEST; @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; @@ -94,28 +87,4 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); verifyNoMoreInteractions(mListener); } - - @Test - public void testCachedRequestsPassedOnRegister() throws Exception { - final List requests = new ArrayList<>(); - - for (int i = 0; i < 10; i++) { - final NetworkRequest request = - new NetworkRequest( - new NetworkCapabilities(), - TEST_LEGACY_TYPE, - i /* requestId */, - TEST_REQUEST_TYPE); - - requests.add(request); - mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); - } - - mVcnNetworkProvider.registerListener(mListener); - for (int i = 0; i < requests.size(); i++) { - final NetworkRequest request = requests.get(i); - verify(mListener).onNetworkRequested(request, i, i + 1); - } - verifyNoMoreInteractions(mListener); - } } From 0c4b535dda282c911ca946c32bac44349bef97e9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 15:55:51 -0700 Subject: [PATCH 0173/1057] Remove unused variable in MtuUtils Bug: 8675309 Test: atest FrameworksNetTests Change-Id: If2abfec1e5755b3f8cc17fb307ec3e1633bb3e18 --- Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java index 49c1a02215..5d40cca3e1 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java @@ -113,7 +113,6 @@ public class MtuUtils { return IPV6_MIN_MTU; } - boolean hasUnknownAlgorithm = false; int maxAuthOverhead = 0; int maxCryptOverhead = 0; int maxAuthCryptOverhead = 0; From 19c46147efe70d3d936438ce4e5dba0145e994d4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 8 Apr 2021 03:18:45 -0700 Subject: [PATCH 0174/1057] Disable INTERNET/DUN when mobile data toggled off This change disables INTERNET and DUN capabilities once the mobile data toggle is turned off. Additionally, when the toggle is flipped, any existing networks advertising either of those two capabilities will be restarted in order to remove the capabilities. Bug: 184864726 Test: atest FrameworksVcnTests Change-Id: I81efeaa4b129443b08a597ff45e0037ddefeb414 --- .../src/com/android/server/vcn/Vcn.java | 152 +++++++++++++++++- .../server/vcn/VcnGatewayConnection.java | 22 ++- ...atewayConnectionDisconnectedStateTest.java | 1 + .../server/vcn/VcnGatewayConnectionTest.java | 28 +++- .../vcn/VcnGatewayConnectionTestBase.java | 1 + .../java/com/android/server/vcn/VcnTest.java | 142 +++++++++++++++- 6 files changed, 326 insertions(+), 20 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 7bc6056f91..70a8a7ff7b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; @@ -26,14 +28,20 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ContentResolver; +import android.database.ContentObserver; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; +import android.provider.Settings; +import android.telephony.TelephonyManager; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -42,9 +50,11 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +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.Map.Entry; import java.util.Objects; @@ -61,6 +71,9 @@ import java.util.Set; public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); + private static final List CAPS_REQUIRING_MOBILE_DATA = + Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); + private static final int MSG_EVENT_BASE = 0; private static final int MSG_CMD_BASE = 100; @@ -110,6 +123,15 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4; + /** + * Triggers reevaluation of mobile data enabled conditions. + * + *

      Upon this notification, the VCN will check if any of the underlying subIds have mobile + * data enabled. If not, the VCN will restart any GatewayConnections providing INTERNET or DUN + * with the current mobile data toggle status. + */ + private static final int MSG_EVENT_MOBILE_DATA_TOGGLED = MSG_EVENT_BASE + 5; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; @@ -118,6 +140,8 @@ public class Vcn extends Handler { @NonNull private final Dependencies mDeps; @NonNull private final VcnNetworkRequestListener mRequestListener; @NonNull private final VcnCallback mVcnCallback; + @NonNull private final VcnContentResolver mContentResolver; + @NonNull private final ContentObserver mMobileDataSettingsObserver; /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. @@ -154,6 +178,8 @@ public class Vcn extends Handler { // Accessed from different threads, but always under lock in VcnManagementService private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE; + private boolean mIsMobileDataEnabled = false; + public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @@ -177,10 +203,19 @@ public class Vcn extends Handler { mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mRequestListener = new VcnNetworkRequestListener(); + mContentResolver = mDeps.newVcnContentResolver(mVcnContext); + mMobileDataSettingsObserver = new VcnMobileDataContentObserver(this /* handler */); + + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + mContentResolver.registerContentObserver( + uri, true /* notifyForDescendants */, mMobileDataSettingsObserver); mConfig = Objects.requireNonNull(config, "Missing config"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); + // Update mIsMobileDataEnabled before starting handling of NetworkRequests. + mIsMobileDataEnabled = getMobileDataStatus(); + // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -260,6 +295,9 @@ public class Vcn extends Handler { case MSG_EVENT_SAFE_MODE_STATE_CHANGED: handleSafeModeStatusChanged(); break; + case MSG_EVENT_MOBILE_DATA_TOGGLED: + handleMobileDataToggled(); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; @@ -366,18 +404,37 @@ public class Vcn extends Handler { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); + if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { + // Skip; this network does not provide any services if mobile data is disabled. + continue; + } + final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( mVcnContext, mSubscriptionGroup, mLastSnapshot, gatewayConnectionConfig, - new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig)); + new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig), + mIsMobileDataEnabled); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } } + private Set getExposedCapabilitiesForMobileDataState( + VcnGatewayConnectionConfig gatewayConnectionConfig) { + if (mIsMobileDataEnabled) { + return gatewayConnectionConfig.getAllExposedCapabilities(); + } + + final Set exposedCapsWithoutMobileData = + new ArraySet<>(gatewayConnectionConfig.getAllExposedCapabilities()); + exposedCapsWithoutMobileData.removeAll(CAPS_REQUIRING_MOBILE_DATA); + + return exposedCapsWithoutMobileData; + } + private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); @@ -396,12 +453,55 @@ public class Vcn extends Handler { } } + private void handleMobileDataToggled() { + final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; + mIsMobileDataEnabled = getMobileDataStatus(); + + if (oldMobileDataEnabledStatus != mIsMobileDataEnabled) { + // Teardown any GatewayConnections that advertise INTERNET or DUN. If they provide other + // services, the VcnGatewayConnections will be restarted without advertising INTERNET or + // DUN. + for (Entry entry : + mVcnGatewayConnections.entrySet()) { + final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); + final VcnGatewayConnection gatewayConnection = entry.getValue(); + + final Set exposedCaps = + gatewayConnectionConfig.getAllExposedCapabilities(); + if (exposedCaps.contains(NET_CAPABILITY_INTERNET) + || exposedCaps.contains(NET_CAPABILITY_DUN)) { + if (gatewayConnection == null) { + Slog.wtf( + getLogTag(), + "Found gatewayConnectionConfig without GatewayConnection"); + } else { + // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown. + gatewayConnection.teardownAsynchronously(); + } + } + } + } + } + + private boolean getMobileDataStatus() { + final TelephonyManager genericTelMan = + mVcnContext.getContext().getSystemService(TelephonyManager.class); + + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { + return true; + } + } + + return false; + } + private boolean isRequestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - for (int cap : config.getAllExposedCapabilities()) { + for (int cap : getExposedCapabilitiesForMobileDataState(config)) { builder.addCapability(cap); } @@ -432,6 +532,16 @@ public class Vcn extends Handler { pw.decreaseIndent(); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + public boolean isMobileDataEnabled() { + return mIsMobileDataEnabled; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setMobileDataEnabled(boolean isMobileDataEnabled) { + mIsMobileDataEnabled = isMobileDataEnabled; + } + /** Retrieves the network score for a VCN Network */ // Package visibility for use in VcnGatewayConnection static int getNetworkScore() { @@ -485,6 +595,17 @@ public class Vcn extends Handler { } } + private class VcnMobileDataContentObserver extends ContentObserver { + private VcnMobileDataContentObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -494,13 +615,36 @@ public class Vcn extends Handler { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, VcnGatewayConnectionConfig connectionConfig, - VcnGatewayStatusCallback gatewayStatusCallback) { + VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled) { return new VcnGatewayConnection( vcnContext, subscriptionGroup, snapshot, connectionConfig, - gatewayStatusCallback); + gatewayStatusCallback, + isMobileDataEnabled); + } + + /** Builds a new VcnContentResolver instance */ + public VcnContentResolver newVcnContentResolver(VcnContext vcnContext) { + return new VcnContentResolver(vcnContext); + } + } + + /** Proxy Implementation of NetworkAgent, used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnContentResolver { + private final ContentResolver mImpl; + + public VcnContentResolver(VcnContext vcnContext) { + mImpl = vcnContext.getContext().getContentResolver(); + } + + /** Registers the content observer */ + public void registerContentObserver( + @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer) { + mImpl.registerContentObserver(uri, notifyForDescendants, observer); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 1d55ba464f..c5a2c7484a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; @@ -517,6 +519,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull private final Dependencies mDeps; @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; + private final boolean mIsMobileDataEnabled; @NonNull private final IpSecManager mIpSecManager; @@ -626,13 +629,15 @@ public class VcnGatewayConnection extends StateMachine { @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, - @NonNull VcnGatewayStatusCallback gatewayStatusCallback) { + @NonNull VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled) { this( vcnContext, subscriptionGroup, snapshot, connectionConfig, gatewayStatusCallback, + isMobileDataEnabled, new Dependencies()); } @@ -643,6 +648,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled, @NonNull Dependencies deps) { super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; @@ -650,6 +656,7 @@ public class VcnGatewayConnection extends StateMachine { mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); mGatewayStatusCallback = Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback"); + mIsMobileDataEnabled = isMobileDataEnabled; mDeps = Objects.requireNonNull(deps, "Missing deps"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); @@ -1502,7 +1509,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull VcnNetworkAgent agent, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = - buildNetworkCapabilities(mConnectionConfig, mUnderlying); + buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( mConnectionConfig, tunnelIface, childConfig, mUnderlying); @@ -1515,7 +1522,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = - buildNetworkCapabilities(mConnectionConfig, mUnderlying); + buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( mConnectionConfig, tunnelIface, childConfig, mUnderlying); @@ -1843,7 +1850,8 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, - @Nullable UnderlyingNetworkRecord underlying) { + @Nullable UnderlyingNetworkRecord underlying, + boolean isMobileDataEnabled) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); @@ -1853,6 +1861,12 @@ public class VcnGatewayConnection extends StateMachine { // Add exposed capabilities for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) { + // Skip adding INTERNET or DUN if mobile data is disabled. + if (!isMobileDataEnabled + && (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN)) { + continue; + } + builder.addCapability(cap); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 5f27fabb62..ac0edaa3b5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -65,6 +65,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mGatewayStatusCallback, + true /* isMobileDataEnabled */, mDeps); vgc.setIsQuitting(true); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index ced8745e89..9705f0fc6b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +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_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; @@ -89,7 +91,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong()); } - private void verifyBuildNetworkCapabilitiesCommon(int transportType) { + private void verifyBuildNetworkCapabilitiesCommon( + int transportType, boolean isMobileDataEnabled) { final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder(); capBuilder.addTransportType(transportType); capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); @@ -109,10 +112,22 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( - VcnGatewayConnectionConfigTest.buildTestConfig(), record); + VcnGatewayConnectionConfigTest.buildTestConfig(), + record, + isMobileDataEnabled); + assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + + for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) { + assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap)); + } else { + assertTrue(vcnCaps.hasCapability(cap)); + } + } + assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); @@ -126,12 +141,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { @Test public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception { - verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI); + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */); } @Test public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception { - verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR); + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */); + } + + @Test + public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception { + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 98d553dab0..284f1f8865 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -202,6 +202,7 @@ public class VcnGatewayConnectionTestBase { TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mGatewayStatusCallback, + true /* isMobileDataEnabled */, mDeps); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 90eb75e865..7c2a5a1cfc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -16,16 +16,24 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static com.android.server.vcn.Vcn.VcnContentResolver; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -35,12 +43,16 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.database.ContentObserver; import android.net.NetworkRequest; +import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; @@ -53,7 +65,10 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -62,14 +77,21 @@ public class VcnTest { private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int NETWORK_SCORE = 0; private static final int PROVIDER_ID = 5; + private static final boolean MOBILE_DATA_ENABLED = true; + private static final Set TEST_SUB_IDS_IN_GROUP = + new ArraySet<>(Arrays.asList(1, 2, 3)); private static final int[][] TEST_CAPS = new int[][] { - new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET}, - new int[] {NET_CAPABILITY_DUN} + new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN}, + new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET}, + new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN}, + new int[] {NET_CAPABILITY_MMS} }; private Context mContext; private VcnContext mVcnContext; + private TelephonyManager mTelephonyManager; + private VcnContentResolver mContentResolver; private TelephonySubscriptionSnapshot mSubscriptionSnapshot; private VcnNetworkProvider mVcnNetworkProvider; private VcnCallback mVcnCallback; @@ -86,6 +108,9 @@ public class VcnTest { public void setUp() { mContext = mock(Context.class); mVcnContext = mock(VcnContext.class); + mTelephonyManager = + setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */); + mContentResolver = mock(VcnContentResolver.class); mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); mVcnNetworkProvider = mock(VcnNetworkProvider.class); mVcnCallback = mock(VcnCallback.class); @@ -97,12 +122,15 @@ public class VcnTest { doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext)); // Setup VcnGatewayConnection instance generation doAnswer((invocation) -> { // Mock-within a doAnswer is safe, because it doesn't actually run nested. return mock(VcnGatewayConnection.class); - }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any()); + }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean()); + + doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any()); mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); @@ -123,6 +151,16 @@ public class VcnTest { mDeps); } + private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) { + final TelephonyManager telephonyManager = mock(TelephonyManager.class); + VcnTestUtils.setupSystemService( + mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt()); + doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled(); + + return telephonyManager; + } + private NetworkRequestListener verifyAndGetRequestListener() { ArgumentCaptor mNetworkRequestListenerCaptor = ArgumentCaptor.forClass(NetworkRequestListener.class); @@ -163,6 +201,39 @@ public class VcnTest { } } + @Test + public void testContentObserverRegistered() { + // Validate state from setUp() + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + verify(mContentResolver) + .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); + } + + @Test + public void testMobileDataStateCheckedOnInitialization_enabled() { + // Validate state from setUp() + assertTrue(mVcn.isMobileDataEnabled()); + verify(mTelephonyManager).isDataEnabled(); + } + + @Test + public void testMobileDataStateCheckedOnInitialization_disabled() { + // Build and setup new telephonyManager to ensure method call count is reset. + final TelephonyManager telephonyManager = + setupAndGetTelephonyManager(false /* isMobileDataEnabled */); + final Vcn vcn = + new Vcn( + mVcnContext, + TEST_SUB_GROUP, + mConfig, + mSubscriptionSnapshot, + mVcnCallback, + mDeps); + + assertFalse(vcn.isMobileDataEnabled()); + verify(mTelephonyManager).isDataEnabled(); + } + @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE); @@ -193,7 +264,8 @@ public class VcnTest { eq(TEST_SUB_GROUP), eq(mSubscriptionSnapshot), any(), - mGatewayStatusCallbackCaptor.capture()); + mGatewayStatusCallbackCaptor.capture(), + eq(MOBILE_DATA_ENABLED)); return gatewayConnections; } @@ -256,20 +328,21 @@ public class VcnTest { mTestLooper.dispatchAll(); // Verify that the VCN requests the networkRequests be resent - assertEquals(1, mVcn.getVcnGatewayConnections().size()); + assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size()); verify(mVcnNetworkProvider).resendAllRequests(requestListener); // Verify that the VcnGatewayConnection is restarted if a request exists for it triggerVcnRequestListeners(requestListener); mTestLooper.dispatchAll(); - assertEquals(2, mVcn.getVcnGatewayConnections().size()); + assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size()); verify(mDeps, times(gatewayConnections.size() + 1)) .newVcnGatewayConnection( eq(mVcnContext), eq(TEST_SUB_GROUP), eq(mSubscriptionSnapshot), any(), - mGatewayStatusCallbackCaptor.capture()); + mGatewayStatusCallbackCaptor.capture(), + anyBoolean()); } @Test @@ -286,7 +359,7 @@ public class VcnTest { public void testUpdateConfigReevaluatesGatewayConnections() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startGatewaysAndGetGatewayConnections(requestListener); - assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size()); + assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size()); // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name @@ -309,4 +382,57 @@ public class VcnTest { verify(removedGatewayConnection).teardownAsynchronously(); verify(mVcnNetworkProvider).resendAllRequests(requestListener); } + + private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + // Start VcnGatewayConnections + mVcn.setMobileDataEnabled(startingToggleState); + triggerVcnRequestListeners(verifyAndGetRequestListener()); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); + + // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the + // toggle state changed. + for (Entry entry : gateways.entrySet()) { + final Set exposedCaps = entry.getKey().getAllExposedCapabilities(); + if (startingToggleState != endingToggleState + && (exposedCaps.contains(NET_CAPABILITY_INTERNET) + || exposedCaps.contains(NET_CAPABILITY_DUN))) { + verify(entry.getValue()).teardownAsynchronously(); + } else { + verify(entry.getValue(), never()).teardownAsynchronously(); + } + } + + assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); + } + + @Test + public void testMobileDataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); + } + + @Test + public void testMobileDataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + } } From 7b811fcee8cd5b0df80cb3d44fa47d7ca55aad5b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 14:41:01 -0700 Subject: [PATCH 0175/1057] Improve dump detail This change improves the formatting and detail provided by the VCN dump Bug: 8675309 Test: atest FrameworksVcnTests Change-Id: I8f13a0d8fe54e9bf8948e9576e9705024fe79611 --- .../android/server/VcnManagementService.java | 36 +++++++++++++++++++ .../vcn/TelephonySubscriptionTracker.java | 12 +++++++ .../server/vcn/UnderlyingNetworkTracker.java | 13 +++++++ .../server/vcn/VcnGatewayConnection.java | 6 ++++ .../server/vcn/VcnNetworkProvider.java | 4 +++ 5 files changed, 71 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 3b31ab272f..f1857b0d81 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -935,13 +935,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.println("VcnManagementService dump:"); pw.increaseIndent(); + pw.println("mNetworkProvider:"); + pw.increaseIndent(); mNetworkProvider.dump(pw); + pw.decreaseIndent(); + pw.println(); + + pw.println("mTrackingNetworkCallback:"); + pw.increaseIndent(); + mTrackingNetworkCallback.dump(pw); + pw.decreaseIndent(); + pw.println(); synchronized (mLock) { + pw.println("mLastSnapshot:"); + pw.increaseIndent(); + mLastSnapshot.dump(pw); + pw.decreaseIndent(); + pw.println(); + pw.println("mVcns:"); + pw.increaseIndent(); for (Vcn vcn : mVcns.values()) { vcn.dump(pw); } + pw.decreaseIndent(); pw.println(); } @@ -1003,6 +1021,24 @@ public class VcnManagementService extends IVcnManagementService.Stub { return false; } + + /** Dumps the state of this snapshot for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("TrackingNetworkCallback:"); + pw.increaseIndent(); + + pw.println("mCaps:"); + pw.increaseIndent(); + synchronized (mCaps) { + for (Entry entry : mCaps.entrySet()) { + pw.println(entry.getKey() + ": " + entry.getValue()); + } + } + pw.decreaseIndent(); + pw.println(); + + pw.decreaseIndent(); + } } /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index d8a145d9ae..19fbdbd860 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -43,6 +43,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import java.util.Collections; import java.util.HashMap; @@ -320,6 +321,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { && mPrivilegedPackages.equals(other.mPrivilegedPackages); } + /** Dumps the state of this snapshot for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("TelephonySubscriptionSnapshot:"); + pw.increaseIndent(); + + pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap); + pw.println("mPrivilegedPackages: " + mPrivilegedPackages); + + pw.decreaseIndent(); + } + @Override public String toString() { return "TelephonySubscriptionSnapshot{ " diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ab9de77005..a59b368ec3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -31,6 +31,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.ArrayList; @@ -396,6 +397,18 @@ public class UnderlyingNetworkTracker { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } + /** Dumps the state of this record for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkRecord:"); + pw.increaseIndent(); + + pw.println("mNetwork: " + network); + pw.println("mNetworkCapabilities: " + networkCapabilities); + pw.println("mLinkProperties: " + linkProperties); + + pw.decreaseIndent(); + } + /** Builder to incrementally construct an UnderlyingNetworkRecord. */ private static class Builder { @NonNull private final Network mNetwork; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index c5a2c7484a..0765a0a435 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2054,6 +2054,12 @@ public class VcnGatewayConnection extends StateMachine { "mNetworkAgent.getNetwork(): " + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + pw.println("mUnderlying:"); + pw.increaseIndent(); + mUnderlying.dump(pw); + pw.decreaseIndent(); + pw.println(); + pw.decreaseIndent(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index be0deb57ee..4de0fdaba6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -163,15 +163,19 @@ public class VcnNetworkProvider extends NetworkProvider { pw.increaseIndent(); pw.println("mListeners:"); + pw.increaseIndent(); for (NetworkRequestListener listener : mListeners) { pw.println(listener); } + pw.decreaseIndent(); pw.println(); pw.println("mRequests.values:"); + pw.increaseIndent(); for (NetworkRequestEntry entry : mRequests.values()) { entry.dump(pw); } + pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); From 4a15035b66bc495974b878b2498aa2cc579d1d16 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 23:18:27 -0700 Subject: [PATCH 0176/1057] Remove use of network scores, and provider IDs in VcnNetworkProvider This change updates the VcnNetworkProvider and associated requestListeners to no longer use the network score and provider IDs, in order to match the new NetworkProvider APIs. Bug: 185204197 Test: atest FrameworksVcnTests Change-Id: I0cabce702cfd8457fd1a152af07a847b87d67028 --- .../src/com/android/server/vcn/Vcn.java | 24 ++----- .../server/vcn/VcnNetworkProvider.java | 66 ++++--------------- .../server/vcn/VcnNetworkProviderTest.java | 41 ++++++++---- .../java/com/android/server/vcn/VcnTest.java | 4 +- 4 files changed, 47 insertions(+), 88 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 70a8a7ff7b..c7c538521d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -265,10 +265,10 @@ public class Vcn extends Handler { private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + public void onNetworkRequested(@NonNull NetworkRequest request) { Objects.requireNonNull(request, "Missing request"); - sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request)); + sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, request)); } } @@ -284,7 +284,7 @@ public class Vcn extends Handler { handleConfigUpdated((VcnConfig) msg.obj); break; case MSG_EVENT_NETWORK_REQUESTED: - handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + handleNetworkRequested((NetworkRequest) msg.obj); break; case MSG_EVENT_SUBSCRIPTIONS_CHANGED: handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); @@ -365,25 +365,9 @@ public class Vcn extends Handler { } } - private void handleNetworkRequested( - @NonNull NetworkRequest request, int score, int providerId) { + private void handleNetworkRequested(@NonNull NetworkRequest request) { Slog.v(getLogTag(), "Received request " + request); - if (score > getNetworkScore()) { - if (VDBG) { - Slog.v( - getLogTag(), - "Request already satisfied by higher-scoring (" - + score - + ") network from " - + "provider " - + providerId - + ": " - + request); - } - return; - } - // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 4de0fdaba6..8adcf95e78 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -23,7 +23,6 @@ import android.content.Context; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.os.Looper; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -31,7 +30,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import java.util.Objects; import java.util.Set; /** @@ -48,11 +46,11 @@ public class VcnNetworkProvider extends NetworkProvider { private final Set mListeners = new ArraySet<>(); /** - * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest + * Cache of NetworkRequest(s). * *

      NetworkRequests are immutable once created, and therefore can be used as stable keys. */ - private final ArrayMap mRequests = new ArrayMap<>(); + private final Set mRequests = new ArraySet<>(); public VcnNetworkProvider(Context context, Looper looper) { super(context, looper, VcnNetworkProvider.class.getSimpleName()); @@ -80,38 +78,28 @@ public class VcnNetworkProvider extends NetworkProvider { /** Sends all cached NetworkRequest(s) to the specified listener. */ @VisibleForTesting(visibility = Visibility.PACKAGE) public void resendAllRequests(@NonNull NetworkRequestListener listener) { - for (NetworkRequestEntry entry : mRequests.values()) { - notifyListenerForEvent(listener, entry); + for (NetworkRequest request : mRequests) { + notifyListenerForEvent(listener, request); } } private void notifyListenerForEvent( - @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { - listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); + @NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) { + listener.onNetworkRequested(request); } @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { if (VDBG) { - Slog.v( - TAG, - "Network requested: Request = " - + request - + ", score = " - + score - + ", providerId = " - + providerId); + Slog.v(TAG, "Network requested: Request = " + request); } - final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId); - - // NetworkRequests are immutable once created, and therefore can be used as stable keys. - mRequests.put(request, entry); + mRequests.add(request); // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on // Default Data Sub, or similar) for (NetworkRequestListener listener : mListeners) { - notifyListenerForEvent(listener, entry); + notifyListenerForEvent(listener, request); } } @@ -120,37 +108,9 @@ public class VcnNetworkProvider extends NetworkProvider { mRequests.remove(request); } - private static class NetworkRequestEntry { - public final NetworkRequest mRequest; - public final int mScore; - public final int mProviderId; - - private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) { - mRequest = Objects.requireNonNull(request, "Missing request"); - mScore = score; - mProviderId = providerId; - } - - /** - * Dumps the state of this NetworkRequestEntry for logging and debugging purposes. - * - *

      PII and credentials MUST NEVER be dumped here. - */ - public void dump(IndentingPrintWriter pw) { - pw.println("NetworkRequestEntry:"); - pw.increaseIndent(); - - pw.println("mRequest: " + mRequest); - pw.println("mScore: " + mScore); - pw.println("mProviderId: " + mProviderId); - - pw.decreaseIndent(); - } - } - // package-private interface NetworkRequestListener { - void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId); + void onNetworkRequested(@NonNull NetworkRequest request); } /** @@ -170,10 +130,10 @@ public class VcnNetworkProvider extends NetworkProvider { pw.decreaseIndent(); pw.println(); - pw.println("mRequests.values:"); + pw.println("mRequests:"); pw.increaseIndent(); - for (NetworkRequestEntry entry : mRequests.values()) { - entry.dump(pw); + for (NetworkRequest request : mRequests) { + pw.println(request); } pw.decreaseIndent(); pw.println(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index f943f34c9d..79cf746f10 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -34,12 +34,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.List; + /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @SmallTest public class VcnNetworkProviderTest { private static final int TEST_SCORE_UNSATISFIED = 0; - private static final int TEST_SCORE_HIGH = 100; private static final int TEST_PROVIDER_ID = 1; @NonNull private final Context mContext; @@ -65,17 +67,7 @@ public class VcnNetworkProviderTest { final NetworkRequest request = mock(NetworkRequest.class); mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); - verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); - } - - @Test - public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider() - throws Exception { - mVcnNetworkProvider.registerListener(mListener); - - final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); - verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); + verify(mListener).onNetworkRequested(request); } @Test @@ -87,4 +79,29 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); verifyNoMoreInteractions(mListener); } + + @Test + public void testCachedRequestsPassedOnRegister() throws Exception { + final List requests = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + // Build unique network requests; in this case, iterate down the capabilities as a way + // to unique-ify requests. + final NetworkRequest request = + new NetworkRequest.Builder().clearCapabilities().addCapability(i).build(); + + requests.add(request); + mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); + } + + // Remove one, and verify that it is never sent to the listeners. + final NetworkRequest removed = requests.remove(0); + mVcnNetworkProvider.onNetworkRequestWithdrawn(removed); + + mVcnNetworkProvider.registerListener(mListener); + for (NetworkRequest request : requests) { + verify(mListener).onNetworkRequested(request); + } + verifyNoMoreInteractions(mListener); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 7c2a5a1cfc..736fabdb1a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -75,8 +75,6 @@ import java.util.UUID; public class VcnTest { private static final String PKG_NAME = VcnTest.class.getPackage().getName(); private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); - private static final int NETWORK_SCORE = 0; - private static final int PROVIDER_ID = 5; private static final boolean MOBILE_DATA_ENABLED = true; private static final Set TEST_SUB_IDS_IN_GROUP = new ArraySet<>(Arrays.asList(1, 2, 3)); @@ -177,7 +175,7 @@ public class VcnTest { requestBuilder.addCapability(netCapability); } - requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID); + requestListener.onNetworkRequested(requestBuilder.build()); mTestLooper.dispatchAll(); } From 13610319a30478f1e76de9744c462a4d604c3e8d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 23:42:59 -0700 Subject: [PATCH 0177/1057] Switch to using NetworkScore instead of legacy integer This change switches the VcnNetworkAgent from using the legacy score integer, and switches to using the new NetworkScore, using the legacy integer as a internal representation. Bug: 185204197 Test: FrameworksVcnTests Change-Id: Ib0690243f176a2f074358fcc8430f1fd7c3d0d3c --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 11 ++++++----- .../com/android/server/vcn/VcnGatewayConnection.java | 5 +++-- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 10 +++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index c7c538521d..cccb0968fc 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -32,6 +32,7 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; @@ -71,6 +72,8 @@ import java.util.Set; public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); + private static final int VCN_LEGACY_SCORE_INT = 52; + private static final List CAPS_REQUIRING_MOBILE_DATA = Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); @@ -527,11 +530,9 @@ public class Vcn extends Handler { } /** Retrieves the network score for a VCN Network */ - // Package visibility for use in VcnGatewayConnection - static int getNetworkScore() { - // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in - // subGrp" value - return 52; + // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider + static NetworkScore getNetworkScore() { + return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build(); } /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 0765a0a435..23fb95b4fa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -49,6 +49,7 @@ import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; +import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; @@ -2203,7 +2204,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull String tag, @NonNull NetworkCapabilities caps, @NonNull LinkProperties lp, - @NonNull int score, + @NonNull NetworkScore score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, @NonNull Consumer networkUnwantedCallback, @@ -2344,7 +2345,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull String tag, @NonNull NetworkCapabilities caps, @NonNull LinkProperties lp, - @NonNull int score, + @NonNull NetworkScore score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, @NonNull Consumer networkUnwantedCallback, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index a2223e8c1e..95a972652b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mNetworkAgent = mock(VcnNetworkAgent.class); doReturn(mNetworkAgent) .when(mDeps) - .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any()); + .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any()); mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); @@ -216,7 +216,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any(), any(), - anyInt(), + any(), any(), any(), any(), @@ -244,7 +244,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(String.class), ncCaptor.capture(), lpCaptor.capture(), - anyInt(), + any(), argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE), any(), any(), @@ -297,7 +297,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection startingInternalAddrs.equals(lp.getLinkAddresses()) && Collections.singletonList(TEST_DNS_ADDR) .equals(lp.getDnsServers())), - anyInt(), + any(), any(), any(), any(), @@ -356,7 +356,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any(), any(), - anyInt(), + any(), any(), any(), unwantedCallbackCaptor.capture(), From 072038eb043e47da16b93d48a4bf055d76490479 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 13 Apr 2021 18:04:38 -0700 Subject: [PATCH 0178/1057] Use #setNetwork and #getNetwork for IkeSessionParams This pacth changes VCN to call #setNetwork and #getNetwork instead of #setConfiguredNetwork and #getConfiguredNetwork because the later two methods will not be APIs. This patch also changes VCN unit tests to build an IkeSessionParams without a Context because the constructor requring a Context is deprecated. Bug: 180521384 Test: FrameworksVcnTests, CtsVcnTestCases Change-Id: I971d0d1b6824890c58263a1960f3b8d0e66fe7d1 --- .../IkeSessionParamsUtils.java | 2 +- .../android/server/vcn/VcnGatewayConnection.java | 2 +- .../net/vcn/VcnControlPlaneIkeConfigTest.java | 14 +------------- .../VcnGatewayConnectionConnectingStateTest.java | 3 +-- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 9d3462cb0b..8950c4bf20 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -83,7 +83,7 @@ public final class IkeSessionParamsUtils { /** Serializes an IkeSessionParams to a PersistableBundle. */ @NonNull public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) { - if (params.getConfiguredNetwork() != null || params.getIke3gppExtension() != null) { + if (params.getNetwork() != null || params.getIke3gppExtension() != null) { throw new IllegalStateException( "Cannot convert a IkeSessionParams with a caller configured network or with" + " 3GPP extension enabled"); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 1d55ba464f..df31221b5d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2106,7 +2106,7 @@ public class VcnGatewayConnection extends StateMachine { (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams()); - builder.setConfiguredNetwork(network); + builder.setNetwork(network); return builder.build(); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java index 2333718d0c..43b80e4c1b 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java @@ -22,12 +22,7 @@ import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Network; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; @@ -56,20 +51,13 @@ public class VcnControlPlaneIkeConfigTest { .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) .build(); - Context mockContext = mock(Context.class); - ConnectivityManager mockConnectManager = mock(ConnectivityManager.class); - doReturn(mockConnectManager) - .when(mockContext) - .getSystemService(Context.CONNECTIVITY_SERVICE); - doReturn(mock(Network.class)).when(mockConnectManager).getActiveNetwork(); - final String serverHostname = "192.0.2.100"; final String testLocalId = "test.client.com"; final String testRemoteId = "test.server.com"; final byte[] psk = "psk".getBytes(); IKE_PARAMS = - new IkeSessionParams.Builder(mockContext) + new IkeSessionParams.Builder() .setServerHostname(serverHostname) .addSaProposal(ikeProposal) .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index bfe8c73d63..acc8bf98e9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -58,8 +58,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio ArgumentCaptor.forClass(IkeSessionParams.class); verify(mDeps).newIkeSession(any(), paramsCaptor.capture(), any(), any(), any()); assertEquals( - TEST_UNDERLYING_NETWORK_RECORD_1.network, - paramsCaptor.getValue().getConfiguredNetwork()); + TEST_UNDERLYING_NETWORK_RECORD_1.network, paramsCaptor.getValue().getNetwork()); } @Test From dcd57ddebe0f990c03e2498cabc8b289e096db64 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 23:54:16 -0700 Subject: [PATCH 0179/1057] Convert VcnNetworkProvider to use NetworkOffers This change brings VcnNetworkProvider to full functionality in the new NetworkProvider paradigm, where NetworkProviders offer networks, and are notified based on NetworkOfferCallbacks. Bug: 185204197 Test: atest FrameworksVcnTests Change-Id: I88c69c0be9f6fd81839fb1595ed00341001694a5 --- .../net/vcn/VcnGatewayConnectionConfig.java | 7 +- .../android/server/VcnManagementService.java | 3 +- .../server/vcn/VcnNetworkProvider.java | 93 +++++++++++++++++-- .../server/vcn/VcnNetworkProviderTest.java | 51 +++++++++- 4 files changed, 140 insertions(+), 14 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 75db3820f5..d7c6fa1822 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -79,7 +79,12 @@ public final class VcnGatewayConnectionConfig { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int MIN_MTU_V6 = 1280; - private static final Set ALLOWED_CAPABILITIES; + /** + * The set of allowed capabilities for exposed capabilities. + * + * @hide + */ + public static final Set ALLOWED_CAPABILITIES; static { Set allowedCaps = new ArraySet<>(); diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f1857b0d81..039f4d9f3c 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -362,8 +362,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkProvider(mNetworkProvider); + mNetworkProvider.register(); mContext.getSystemService(ConnectivityManager.class) .registerNetworkCallback( new NetworkRequest.Builder().clearCapabilities().build(), diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 8adcf95e78..72cd788032 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -16,12 +16,24 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +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 com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; +import android.net.NetworkScore; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; import android.util.Slog; @@ -30,7 +42,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.Executor; /** * VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed. @@ -45,6 +59,10 @@ public class VcnNetworkProvider extends NetworkProvider { private final Set mListeners = new ArraySet<>(); + private final Context mContext; + private final Handler mHandler; + private final Dependencies mDeps; + /** * Cache of NetworkRequest(s). * @@ -52,8 +70,59 @@ public class VcnNetworkProvider extends NetworkProvider { */ private final Set mRequests = new ArraySet<>(); - public VcnNetworkProvider(Context context, Looper looper) { - super(context, looper, VcnNetworkProvider.class.getSimpleName()); + public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { + this(context, looper, new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnNetworkProvider( + @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) { + super( + Objects.requireNonNull(context, "Missing context"), + Objects.requireNonNull(looper, "Missing looper"), + TAG); + + mContext = context; + mHandler = new Handler(looper); + mDeps = Objects.requireNonNull(dependencies, "Missing dependencies"); + } + + /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */ + public void register() { + mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this); + mDeps.registerNetworkOffer( + this, + Vcn.getNetworkScore(), // score filter + buildCapabilityFilter(), + new HandlerExecutor(mHandler), + new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull NetworkRequest request) { + handleNetworkRequested(request); + } + + @Override + public void onNetworkUnneeded(@NonNull NetworkRequest request) { + handleNetworkRequestWithdrawn(request); + } + }); + } + + /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */ + private NetworkCapabilities buildCapabilityFilter() { + final NetworkCapabilities.Builder builder = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_TRUSTED) + .addCapability(NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NET_CAPABILITY_NOT_VPN) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + + for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) { + builder.addCapability(cap); + } + + return builder.build(); } /** @@ -88,8 +157,7 @@ public class VcnNetworkProvider extends NetworkProvider { listener.onNetworkRequested(request); } - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + private void handleNetworkRequested(@NonNull NetworkRequest request) { if (VDBG) { Slog.v(TAG, "Network requested: Request = " + request); } @@ -103,8 +171,7 @@ public class VcnNetworkProvider extends NetworkProvider { } } - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) { mRequests.remove(request); } @@ -140,4 +207,18 @@ public class VcnNetworkProvider extends NetworkProvider { pw.decreaseIndent(); } + + /** Proxy class for dependencies used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Registers a given network offer for the given provider. */ + public void registerNetworkOffer( + @NonNull VcnNetworkProvider provider, + @NonNull NetworkScore score, + @NonNull NetworkCapabilities capabilitiesFilter, + @NonNull Executor executor, + @NonNull NetworkOfferCallback callback) { + provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback); + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index 79cf746f10..72db55b3f4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -16,12 +16,18 @@ package com.android.server.vcn; +import static android.net.NetworkProvider.NetworkOfferCallback; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; import android.net.NetworkRequest; import android.os.test.TestLooper; @@ -33,6 +39,7 @@ import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.List; @@ -47,6 +54,8 @@ public class VcnNetworkProviderTest { @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; + @NonNull private VcnNetworkProvider.Dependencies mDeps; + @NonNull private ConnectivityManager mConnMgr; @NonNull private VcnNetworkProvider mVcnNetworkProvider; @NonNull private NetworkRequestListener mListener; @@ -57,16 +66,47 @@ public class VcnNetworkProviderTest { @Before public void setUp() throws Exception { - mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper()); + mDeps = mock(VcnNetworkProvider.Dependencies.class); + mConnMgr = mock(ConnectivityManager.class); + VcnTestUtils.setupSystemService( + mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + + mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps); mListener = mock(NetworkRequestListener.class); } + private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception { + mVcnNetworkProvider.register(); + + final ArgumentCaptor cbCaptor = + ArgumentCaptor.forClass(NetworkOfferCallback.class); + + verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider)); + verify(mDeps) + .registerNetworkOffer( + eq(mVcnNetworkProvider), + argThat( + score -> + score.getLegacyInt() + == Vcn.getNetworkScore().getLegacyInt()), + any(), + any(), + cbCaptor.capture()); + + return cbCaptor.getValue(); + } + + @Test + public void testRegister() throws Exception { + verifyRegisterAndGetOfferCallback(); + } + @Test public void testRequestsPassedToRegisteredListeners() throws Exception { mVcnNetworkProvider.registerListener(mListener); final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verifyRegisterAndGetOfferCallback().onNetworkNeeded(request); verify(mListener).onNetworkRequested(request); } @@ -76,13 +116,14 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.unregisterListener(mListener); final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verifyRegisterAndGetOfferCallback().onNetworkNeeded(request); verifyNoMoreInteractions(mListener); } @Test public void testCachedRequestsPassedOnRegister() throws Exception { final List requests = new ArrayList<>(); + final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback(); for (int i = 0; i < 10; i++) { // Build unique network requests; in this case, iterate down the capabilities as a way @@ -91,12 +132,12 @@ public class VcnNetworkProviderTest { new NetworkRequest.Builder().clearCapabilities().addCapability(i).build(); requests.add(request); - mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); + offerCb.onNetworkNeeded(request); } // Remove one, and verify that it is never sent to the listeners. final NetworkRequest removed = requests.remove(0); - mVcnNetworkProvider.onNetworkRequestWithdrawn(removed); + offerCb.onNetworkUnneeded(removed); mVcnNetworkProvider.registerListener(mListener); for (NetworkRequest request : requests) { From 877076fa3e760451f20805158d82b643b51a4556 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 14 Apr 2021 23:33:31 +0800 Subject: [PATCH 0180/1057] [VCN19] Rename get/setSubIds to get/setSubscriptionIds Test: atest FrameworksNetTests FrameworksVcnTests Fix: 185215036 Ignore-AOSP-First: avoid merge conflict Change-Id: I9d90df5fc13b36d2cdc4920b456dcc87fcd2b3a7 --- .../src/com/android/server/VcnManagementService.java | 6 +++--- .../com/android/server/vcn/UnderlyingNetworkTracker.java | 8 ++++---- .../java/com/android/server/VcnManagementServiceTest.java | 2 +- .../android/server/vcn/UnderlyingNetworkTrackerTest.java | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 039f4d9f3c..4b5205711f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -729,7 +729,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // If multiple subscription IDs exist, they MUST all point to the same subscription // group. Otherwise undefined behavior may occur. - for (int subId : networkCapabilities.getSubIds()) { + for (int subId : networkCapabilities.getSubscriptionIds()) { // Verify that all subscriptions point to the same group if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { Slog.wtf(TAG, "Got multiple subscription groups for a single network"); @@ -1003,14 +1003,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { } private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) { - if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) { + if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) { return false; } synchronized (mCaps) { for (NetworkCapabilities existing : mCaps.values()) { if (existing.hasTransport(TRANSPORT_WIFI) - && caps.getSubIds().equals(existing.getSubIds())) { + && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) { // Restart if any immutable capabilities have changed return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index a59b368ec3..1c336041f9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -154,14 +154,14 @@ public class UnderlyingNetworkTracker { * Builds the Route selection request * *

      This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue - * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier - * owned networks may be selected, as the request specifies only subIds in the VCN's + * of a populated set of subIds as expressed in NetworkCapabilities#getSubscriptionIds(). Only + * carrier owned networks may be selected, as the request specifies only subIds in the VCN's * subscription group, while the VCN networks are excluded by virtue of not having subIds set on * the VCN-exposed networks. */ private NetworkRequest getRouteSelectionRequest() { return getBaseNetworkRequestBuilder() - .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } @@ -177,7 +177,7 @@ public class UnderlyingNetworkTracker { private NetworkRequest getWifiNetworkRequest() { return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 9a663436f9..907cb46d29 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -696,7 +696,7 @@ public class VcnManagementServiceTest { .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .addTransportType(transport); if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - ncBuilder.setSubIds(Collections.singleton(subId)); + ncBuilder.setSubscriptionIds(Collections.singleton(subId)); } return ncBuilder; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index b592000e38..65580d6139 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -191,7 +191,7 @@ public class UnderlyingNetworkTrackerTest { private NetworkRequest getWifiRequest(Set netCapsSubIds) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubIds(netCapsSubIds) + .setSubscriptionIds(netCapsSubIds) .build(); } @@ -203,7 +203,7 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { - return getExpectedRequestBase().setSubIds(netCapsSubIds).build(); + return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); } private NetworkRequest.Builder getExpectedRequestBase() { From 2d68d15dee29e87c8621d54ea5aa7713351786ff Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 15 Apr 2021 00:39:49 +0800 Subject: [PATCH 0181/1057] [VCN20] Change requestBackgroundNetwork argument order Test: atest FrameworksNetTests FrameworksVcnTests Fix: 185215095 Ignore-AOSP-First: avoid build break caused by multipatch automerge Change-Id: Id281678fe85ce0894b0e92e11c0283d4d1b4ecdb --- .../server/vcn/UnderlyingNetworkTracker.java | 6 +++--- .../server/vcn/UnderlyingNetworkTrackerTest.java | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index a59b368ec3..48ccad33e6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -119,18 +119,18 @@ public class UnderlyingNetworkTracker { if (!mIsQuitting) { mRouteSelectionCallback = new RouteSelectionCallback(); mConnectivityManager.requestBackgroundNetwork( - getRouteSelectionRequest(), mHandler, mRouteSelectionCallback); + getRouteSelectionRequest(), mRouteSelectionCallback, mHandler); mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( - getWifiNetworkRequest(), mHandler, mWifiBringupCallback); + getWifiNetworkRequest(), mWifiBringupCallback, mHandler); for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { final NetworkBringupCallback cb = new NetworkBringupCallback(); mCellBringupCallbacks.add(cb); mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), mHandler, cb); + getCellNetworkRequestForSubId(subId), cb, mHandler); } } else { mRouteSelectionCallback = null; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index b592000e38..0c7363e55c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -153,21 +153,19 @@ public class UnderlyingNetworkTrackerTest { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getWifiRequest(expectedSubIds)), - any(), - any(NetworkBringupCallback.class)); + any(NetworkBringupCallback.class), + any()); for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getCellRequestForSubId(subId)), - any(), - any(NetworkBringupCallback.class)); + any(NetworkBringupCallback.class), any()); } verify(mConnectivityManager) .requestBackgroundNetwork( eq(getRouteSelectionRequest(expectedSubIds)), - any(), - any(RouteSelectionCallback.class)); + any(RouteSelectionCallback.class), any()); } @Test @@ -267,8 +265,8 @@ public class UnderlyingNetworkTrackerTest { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), - any(), - mRouteSelectionCallbackCaptor.capture()); + mRouteSelectionCallbackCaptor.capture(), + any()); RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); cb.onAvailable(mNetwork); From 6ee5ab4d240cf60aabf0ba49faaa15668bd98317 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 15 Apr 2021 00:39:49 +0800 Subject: [PATCH 0182/1057] [VCN20] Change requestBackgroundNetwork argument order Test: atest FrameworksNetTests FrameworksVcnTests Fix: 185215095 Merged-In: Id281678fe85ce0894b0e92e11c0283d4d1b4ecdb Change-Id: Id281678fe85ce0894b0e92e11c0283d4d1b4ecdb (cherry-picked from ag/14198667) --- .../server/vcn/UnderlyingNetworkTracker.java | 6 +++--- .../server/vcn/UnderlyingNetworkTrackerTest.java | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ab9de77005..ab214e8329 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -118,18 +118,18 @@ public class UnderlyingNetworkTracker { if (!mIsQuitting) { mRouteSelectionCallback = new RouteSelectionCallback(); mConnectivityManager.requestBackgroundNetwork( - getRouteSelectionRequest(), mHandler, mRouteSelectionCallback); + getRouteSelectionRequest(), mRouteSelectionCallback, mHandler); mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( - getWifiNetworkRequest(), mHandler, mWifiBringupCallback); + getWifiNetworkRequest(), mWifiBringupCallback, mHandler); for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { final NetworkBringupCallback cb = new NetworkBringupCallback(); mCellBringupCallbacks.add(cb); mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), mHandler, cb); + getCellNetworkRequestForSubId(subId), cb, mHandler); } } else { mRouteSelectionCallback = null; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index b592000e38..0c7363e55c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -153,21 +153,19 @@ public class UnderlyingNetworkTrackerTest { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getWifiRequest(expectedSubIds)), - any(), - any(NetworkBringupCallback.class)); + any(NetworkBringupCallback.class), + any()); for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getCellRequestForSubId(subId)), - any(), - any(NetworkBringupCallback.class)); + any(NetworkBringupCallback.class), any()); } verify(mConnectivityManager) .requestBackgroundNetwork( eq(getRouteSelectionRequest(expectedSubIds)), - any(), - any(RouteSelectionCallback.class)); + any(RouteSelectionCallback.class), any()); } @Test @@ -267,8 +265,8 @@ public class UnderlyingNetworkTrackerTest { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), - any(), - mRouteSelectionCallbackCaptor.capture()); + mRouteSelectionCallbackCaptor.capture(), + any()); RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); cb.onAvailable(mNetwork); From e535f7f80ddfd1c033006e226fd79aff026fce4e Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 14 Apr 2021 23:33:31 +0800 Subject: [PATCH 0183/1057] [VCN19] Rename get/setSubIds to get/setSubscriptionIds Test: atest FrameworksNetTests FrameworksVcnTests Fix: 185215036 Merged-In: I9d90df5fc13b36d2cdc4920b456dcc87fcd2b3a7 Change-Id: I9d90df5fc13b36d2cdc4920b456dcc87fcd2b3a7 (cherry-picked from ag/14198665) --- .../src/com/android/server/VcnManagementService.java | 6 +++--- .../com/android/server/vcn/UnderlyingNetworkTracker.java | 8 ++++---- .../java/com/android/server/VcnManagementServiceTest.java | 2 +- .../android/server/vcn/UnderlyingNetworkTrackerTest.java | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 9c10658e7c..5898c56b6f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -731,7 +731,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // If multiple subscription IDs exist, they MUST all point to the same subscription // group. Otherwise undefined behavior may occur. - for (int subId : networkCapabilities.getSubIds()) { + for (int subId : networkCapabilities.getSubscriptionIds()) { // Verify that all subscriptions point to the same group if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { Slog.wtf(TAG, "Got multiple subscription groups for a single network"); @@ -987,14 +987,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { } private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) { - if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) { + if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) { return false; } synchronized (mCaps) { for (NetworkCapabilities existing : mCaps.values()) { if (existing.hasTransport(TRANSPORT_WIFI) - && caps.getSubIds().equals(existing.getSubIds())) { + && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) { // Restart if any immutable capabilities have changed return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ab214e8329..c27766e03f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -153,14 +153,14 @@ public class UnderlyingNetworkTracker { * Builds the Route selection request * *

      This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue - * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier - * owned networks may be selected, as the request specifies only subIds in the VCN's + * of a populated set of subIds as expressed in NetworkCapabilities#getSubscriptionIds(). Only + * carrier owned networks may be selected, as the request specifies only subIds in the VCN's * subscription group, while the VCN networks are excluded by virtue of not having subIds set on * the VCN-exposed networks. */ private NetworkRequest getRouteSelectionRequest() { return getBaseNetworkRequestBuilder() - .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } @@ -176,7 +176,7 @@ public class UnderlyingNetworkTracker { private NetworkRequest getWifiNetworkRequest() { return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index bbc9bb600f..ebb3d34499 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -696,7 +696,7 @@ public class VcnManagementServiceTest { .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .addTransportType(transport); if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - ncBuilder.setSubIds(Collections.singleton(subId)); + ncBuilder.setSubscriptionIds(Collections.singleton(subId)); } return ncBuilder; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 0c7363e55c..8289e85dad 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -189,7 +189,7 @@ public class UnderlyingNetworkTrackerTest { private NetworkRequest getWifiRequest(Set netCapsSubIds) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubIds(netCapsSubIds) + .setSubscriptionIds(netCapsSubIds) .build(); } @@ -201,7 +201,7 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { - return getExpectedRequestBase().setSubIds(netCapsSubIds).build(); + return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); } private NetworkRequest.Builder getExpectedRequestBase() { From 194a41b056f1cb120cb99798fcf114b8a6ff2287 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 13 Apr 2021 18:34:51 +0800 Subject: [PATCH 0184/1057] Remove hidden connectivity method access in FrameworksVcnTests Due to connectivity modularization work, hidden connectivity methods and members are not accessible outside the module. Remove the corresponding usage. The test case in VcnNetworkProviderTest are not able to create NetworkRequests with request id assigned. The loop to create different request is removed. After that, the test does not provide more test coverage than other tests. Thus, Remove the test case directly. Bug: 182859030 Test: atest FrameworksVcnTests Merged-In: I488f62089d1dbe93c232f892885d944bef896df6 Change-Id: I488f62089d1dbe93c232f892885d944bef896df6 (cherry picked from commit 578d519d49d64e11c3d97aeb7f6c2c8cf18aee3f) --- .../server/VcnManagementServiceTest.java | 6 ++-- .../server/vcn/VcnGatewayConnectionTest.java | 30 +++++++++--------- .../vcn/VcnGatewayConnectionTestBase.java | 5 +-- .../server/vcn/VcnNetworkProviderTest.java | 31 ------------------- 4 files changed, 22 insertions(+), 50 deletions(-) diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index bbc9bb600f..9a663436f9 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -39,6 +39,7 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; @@ -59,7 +60,6 @@ import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkCapabilities.Transport; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnStatusCallback; @@ -657,7 +657,7 @@ public class VcnManagementServiceTest { private void verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, - @Transport int transportType, + int transportType, boolean isVcnManaged, boolean isRestricted) { assertTrue(mergedCapabilities.hasTransport(transportType)); @@ -779,7 +779,7 @@ public class VcnManagementServiceTest { .registerNetworkCallback( eq(new NetworkRequest.Builder().clearCapabilities().build()), captor.capture()); - captor.getValue().onCapabilitiesChanged(new Network(0), caps); + captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index d08af9dd33..ced8745e89 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -25,7 +25,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -83,31 +86,30 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { super.setUp(); mWifiInfo = mock(WifiInfo.class); + doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong()); } private void verifyBuildNetworkCapabilitiesCommon(int transportType) { - final NetworkCapabilities underlyingCaps = new NetworkCapabilities(); - underlyingCaps.addTransportType(transportType); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED); - underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING); + final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder(); + capBuilder.addTransportType(transportType); + capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + capBuilder.addCapability(NET_CAPABILITY_NOT_METERED); + capBuilder.addCapability(NET_CAPABILITY_NOT_ROAMING); if (transportType == TRANSPORT_WIFI) { - underlyingCaps.setTransportInfo(mWifiInfo); - underlyingCaps.setOwnerUid(TEST_UID); + capBuilder.setTransportInfo(mWifiInfo); + capBuilder.setOwnerUid(TEST_UID); } else if (transportType == TRANSPORT_CELLULAR) { - underlyingCaps.setAdministratorUids(new int[] {TEST_UID}); - underlyingCaps.setNetworkSpecifier( + capBuilder.setNetworkSpecifier( new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); } - - UnderlyingNetworkRecord record = - new UnderlyingNetworkRecord( - new Network(0), underlyingCaps, new LinkProperties(), false); + capBuilder.setAdministratorUids(new int[] {TEST_UID}); + UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( VcnGatewayConnectionConfigTest.buildTestConfig(), record); - assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index dc73be25ff..98d553dab0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -93,7 +94,7 @@ public class VcnGatewayConnectionTestBase { protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( - new Network(0), + mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), false /* blocked */); @@ -104,7 +105,7 @@ public class VcnGatewayConnectionTestBase { protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = new UnderlyingNetworkRecord( - new Network(1), + mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), false /* blocked */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index c2c6200fd5..f943f34c9d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -22,8 +22,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.test.TestLooper; @@ -36,9 +34,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.ArrayList; -import java.util.List; - /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @SmallTest @@ -46,8 +41,6 @@ public class VcnNetworkProviderTest { private static final int TEST_SCORE_UNSATISFIED = 0; private static final int TEST_SCORE_HIGH = 100; private static final int TEST_PROVIDER_ID = 1; - private static final int TEST_LEGACY_TYPE = ConnectivityManager.TYPE_MOBILE; - private static final NetworkRequest.Type TEST_REQUEST_TYPE = NetworkRequest.Type.REQUEST; @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; @@ -94,28 +87,4 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); verifyNoMoreInteractions(mListener); } - - @Test - public void testCachedRequestsPassedOnRegister() throws Exception { - final List requests = new ArrayList<>(); - - for (int i = 0; i < 10; i++) { - final NetworkRequest request = - new NetworkRequest( - new NetworkCapabilities(), - TEST_LEGACY_TYPE, - i /* requestId */, - TEST_REQUEST_TYPE); - - requests.add(request); - mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); - } - - mVcnNetworkProvider.registerListener(mListener); - for (int i = 0; i < requests.size(); i++) { - final NetworkRequest request = requests.get(i); - verify(mListener).onNetworkRequested(request, i, i + 1); - } - verifyNoMoreInteractions(mListener); - } } From a1105a9aed8486741d64bb5f46e635b3f694c839 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 8 Apr 2021 03:18:45 -0700 Subject: [PATCH 0185/1057] Disable INTERNET/DUN when mobile data toggled off This change disables INTERNET and DUN capabilities once the mobile data toggle is turned off. Additionally, when the toggle is flipped, any existing networks advertising either of those two capabilities will be restarted in order to remove the capabilities. Bug: 184864726 Test: atest FrameworksVcnTests Merged-In: I81efeaa4b129443b08a597ff45e0037ddefeb414 Change-Id: I81efeaa4b129443b08a597ff45e0037ddefeb414 (cherry picked from commit 19c46147efe70d3d936438ce4e5dba0145e994d4) --- .../src/com/android/server/vcn/Vcn.java | 152 +++++++++++++++++- .../server/vcn/VcnGatewayConnection.java | 22 ++- ...atewayConnectionDisconnectedStateTest.java | 1 + .../server/vcn/VcnGatewayConnectionTest.java | 28 +++- .../vcn/VcnGatewayConnectionTestBase.java | 1 + .../java/com/android/server/vcn/VcnTest.java | 142 +++++++++++++++- 6 files changed, 326 insertions(+), 20 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 7bc6056f91..70a8a7ff7b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; @@ -26,14 +28,20 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ContentResolver; +import android.database.ContentObserver; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; +import android.provider.Settings; +import android.telephony.TelephonyManager; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -42,9 +50,11 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +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.Map.Entry; import java.util.Objects; @@ -61,6 +71,9 @@ import java.util.Set; public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); + private static final List CAPS_REQUIRING_MOBILE_DATA = + Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); + private static final int MSG_EVENT_BASE = 0; private static final int MSG_CMD_BASE = 100; @@ -110,6 +123,15 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4; + /** + * Triggers reevaluation of mobile data enabled conditions. + * + *

      Upon this notification, the VCN will check if any of the underlying subIds have mobile + * data enabled. If not, the VCN will restart any GatewayConnections providing INTERNET or DUN + * with the current mobile data toggle status. + */ + private static final int MSG_EVENT_MOBILE_DATA_TOGGLED = MSG_EVENT_BASE + 5; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; @@ -118,6 +140,8 @@ public class Vcn extends Handler { @NonNull private final Dependencies mDeps; @NonNull private final VcnNetworkRequestListener mRequestListener; @NonNull private final VcnCallback mVcnCallback; + @NonNull private final VcnContentResolver mContentResolver; + @NonNull private final ContentObserver mMobileDataSettingsObserver; /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. @@ -154,6 +178,8 @@ public class Vcn extends Handler { // Accessed from different threads, but always under lock in VcnManagementService private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE; + private boolean mIsMobileDataEnabled = false; + public Vcn( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @@ -177,10 +203,19 @@ public class Vcn extends Handler { mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mRequestListener = new VcnNetworkRequestListener(); + mContentResolver = mDeps.newVcnContentResolver(mVcnContext); + mMobileDataSettingsObserver = new VcnMobileDataContentObserver(this /* handler */); + + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + mContentResolver.registerContentObserver( + uri, true /* notifyForDescendants */, mMobileDataSettingsObserver); mConfig = Objects.requireNonNull(config, "Missing config"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); + // Update mIsMobileDataEnabled before starting handling of NetworkRequests. + mIsMobileDataEnabled = getMobileDataStatus(); + // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -260,6 +295,9 @@ public class Vcn extends Handler { case MSG_EVENT_SAFE_MODE_STATE_CHANGED: handleSafeModeStatusChanged(); break; + case MSG_EVENT_MOBILE_DATA_TOGGLED: + handleMobileDataToggled(); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; @@ -366,18 +404,37 @@ public class Vcn extends Handler { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); + if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { + // Skip; this network does not provide any services if mobile data is disabled. + continue; + } + final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( mVcnContext, mSubscriptionGroup, mLastSnapshot, gatewayConnectionConfig, - new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig)); + new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig), + mIsMobileDataEnabled); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } } + private Set getExposedCapabilitiesForMobileDataState( + VcnGatewayConnectionConfig gatewayConnectionConfig) { + if (mIsMobileDataEnabled) { + return gatewayConnectionConfig.getAllExposedCapabilities(); + } + + final Set exposedCapsWithoutMobileData = + new ArraySet<>(gatewayConnectionConfig.getAllExposedCapabilities()); + exposedCapsWithoutMobileData.removeAll(CAPS_REQUIRING_MOBILE_DATA); + + return exposedCapsWithoutMobileData; + } + private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); @@ -396,12 +453,55 @@ public class Vcn extends Handler { } } + private void handleMobileDataToggled() { + final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; + mIsMobileDataEnabled = getMobileDataStatus(); + + if (oldMobileDataEnabledStatus != mIsMobileDataEnabled) { + // Teardown any GatewayConnections that advertise INTERNET or DUN. If they provide other + // services, the VcnGatewayConnections will be restarted without advertising INTERNET or + // DUN. + for (Entry entry : + mVcnGatewayConnections.entrySet()) { + final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); + final VcnGatewayConnection gatewayConnection = entry.getValue(); + + final Set exposedCaps = + gatewayConnectionConfig.getAllExposedCapabilities(); + if (exposedCaps.contains(NET_CAPABILITY_INTERNET) + || exposedCaps.contains(NET_CAPABILITY_DUN)) { + if (gatewayConnection == null) { + Slog.wtf( + getLogTag(), + "Found gatewayConnectionConfig without GatewayConnection"); + } else { + // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown. + gatewayConnection.teardownAsynchronously(); + } + } + } + } + } + + private boolean getMobileDataStatus() { + final TelephonyManager genericTelMan = + mVcnContext.getContext().getSystemService(TelephonyManager.class); + + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { + return true; + } + } + + return false; + } + private boolean isRequestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - for (int cap : config.getAllExposedCapabilities()) { + for (int cap : getExposedCapabilitiesForMobileDataState(config)) { builder.addCapability(cap); } @@ -432,6 +532,16 @@ public class Vcn extends Handler { pw.decreaseIndent(); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + public boolean isMobileDataEnabled() { + return mIsMobileDataEnabled; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setMobileDataEnabled(boolean isMobileDataEnabled) { + mIsMobileDataEnabled = isMobileDataEnabled; + } + /** Retrieves the network score for a VCN Network */ // Package visibility for use in VcnGatewayConnection static int getNetworkScore() { @@ -485,6 +595,17 @@ public class Vcn extends Handler { } } + private class VcnMobileDataContentObserver extends ContentObserver { + private VcnMobileDataContentObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -494,13 +615,36 @@ public class Vcn extends Handler { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, VcnGatewayConnectionConfig connectionConfig, - VcnGatewayStatusCallback gatewayStatusCallback) { + VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled) { return new VcnGatewayConnection( vcnContext, subscriptionGroup, snapshot, connectionConfig, - gatewayStatusCallback); + gatewayStatusCallback, + isMobileDataEnabled); + } + + /** Builds a new VcnContentResolver instance */ + public VcnContentResolver newVcnContentResolver(VcnContext vcnContext) { + return new VcnContentResolver(vcnContext); + } + } + + /** Proxy Implementation of NetworkAgent, used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class VcnContentResolver { + private final ContentResolver mImpl; + + public VcnContentResolver(VcnContext vcnContext) { + mImpl = vcnContext.getContext().getContentResolver(); + } + + /** Registers the content observer */ + public void registerContentObserver( + @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer) { + mImpl.registerContentObserver(uri, notifyForDescendants, observer); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index df31221b5d..8847dda71c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; @@ -517,6 +519,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull private final Dependencies mDeps; @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; + private final boolean mIsMobileDataEnabled; @NonNull private final IpSecManager mIpSecManager; @@ -626,13 +629,15 @@ public class VcnGatewayConnection extends StateMachine { @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, - @NonNull VcnGatewayStatusCallback gatewayStatusCallback) { + @NonNull VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled) { this( vcnContext, subscriptionGroup, snapshot, connectionConfig, gatewayStatusCallback, + isMobileDataEnabled, new Dependencies()); } @@ -643,6 +648,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull VcnGatewayStatusCallback gatewayStatusCallback, + boolean isMobileDataEnabled, @NonNull Dependencies deps) { super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper()); mVcnContext = vcnContext; @@ -650,6 +656,7 @@ public class VcnGatewayConnection extends StateMachine { mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); mGatewayStatusCallback = Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback"); + mIsMobileDataEnabled = isMobileDataEnabled; mDeps = Objects.requireNonNull(deps, "Missing deps"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); @@ -1502,7 +1509,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull VcnNetworkAgent agent, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = - buildNetworkCapabilities(mConnectionConfig, mUnderlying); + buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( mConnectionConfig, tunnelIface, childConfig, mUnderlying); @@ -1515,7 +1522,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig) { final NetworkCapabilities caps = - buildNetworkCapabilities(mConnectionConfig, mUnderlying); + buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( mConnectionConfig, tunnelIface, childConfig, mUnderlying); @@ -1843,7 +1850,8 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, - @Nullable UnderlyingNetworkRecord underlying) { + @Nullable UnderlyingNetworkRecord underlying, + boolean isMobileDataEnabled) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); @@ -1853,6 +1861,12 @@ public class VcnGatewayConnection extends StateMachine { // Add exposed capabilities for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) { + // Skip adding INTERNET or DUN if mobile data is disabled. + if (!isMobileDataEnabled + && (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN)) { + continue; + } + builder.addCapability(cap); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 5f27fabb62..ac0edaa3b5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -65,6 +65,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mGatewayStatusCallback, + true /* isMobileDataEnabled */, mDeps); vgc.setIsQuitting(true); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index ced8745e89..9705f0fc6b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +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_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; @@ -89,7 +91,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong()); } - private void verifyBuildNetworkCapabilitiesCommon(int transportType) { + private void verifyBuildNetworkCapabilitiesCommon( + int transportType, boolean isMobileDataEnabled) { final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder(); capBuilder.addTransportType(transportType); capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); @@ -109,10 +112,22 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( - VcnGatewayConnectionConfigTest.buildTestConfig(), record); + VcnGatewayConnectionConfigTest.buildTestConfig(), + record, + isMobileDataEnabled); + assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + + for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) { + assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap)); + } else { + assertTrue(vcnCaps.hasCapability(cap)); + } + } + assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); @@ -126,12 +141,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { @Test public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception { - verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI); + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */); } @Test public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception { - verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR); + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */); + } + + @Test + public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception { + verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 98d553dab0..284f1f8865 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -202,6 +202,7 @@ public class VcnGatewayConnectionTestBase { TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mGatewayStatusCallback, + true /* isMobileDataEnabled */, mDeps); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 90eb75e865..7c2a5a1cfc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -16,16 +16,24 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static com.android.server.vcn.Vcn.VcnContentResolver; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -35,12 +43,16 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.database.ContentObserver; import android.net.NetworkRequest; +import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; @@ -53,7 +65,10 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -62,14 +77,21 @@ public class VcnTest { private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int NETWORK_SCORE = 0; private static final int PROVIDER_ID = 5; + private static final boolean MOBILE_DATA_ENABLED = true; + private static final Set TEST_SUB_IDS_IN_GROUP = + new ArraySet<>(Arrays.asList(1, 2, 3)); private static final int[][] TEST_CAPS = new int[][] { - new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET}, - new int[] {NET_CAPABILITY_DUN} + new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN}, + new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET}, + new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN}, + new int[] {NET_CAPABILITY_MMS} }; private Context mContext; private VcnContext mVcnContext; + private TelephonyManager mTelephonyManager; + private VcnContentResolver mContentResolver; private TelephonySubscriptionSnapshot mSubscriptionSnapshot; private VcnNetworkProvider mVcnNetworkProvider; private VcnCallback mVcnCallback; @@ -86,6 +108,9 @@ public class VcnTest { public void setUp() { mContext = mock(Context.class); mVcnContext = mock(VcnContext.class); + mTelephonyManager = + setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */); + mContentResolver = mock(VcnContentResolver.class); mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class); mVcnNetworkProvider = mock(VcnNetworkProvider.class); mVcnCallback = mock(VcnCallback.class); @@ -97,12 +122,15 @@ public class VcnTest { doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext)); // Setup VcnGatewayConnection instance generation doAnswer((invocation) -> { // Mock-within a doAnswer is safe, because it doesn't actually run nested. return mock(VcnGatewayConnection.class); - }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any()); + }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean()); + + doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any()); mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); @@ -123,6 +151,16 @@ public class VcnTest { mDeps); } + private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) { + final TelephonyManager telephonyManager = mock(TelephonyManager.class); + VcnTestUtils.setupSystemService( + mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt()); + doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled(); + + return telephonyManager; + } + private NetworkRequestListener verifyAndGetRequestListener() { ArgumentCaptor mNetworkRequestListenerCaptor = ArgumentCaptor.forClass(NetworkRequestListener.class); @@ -163,6 +201,39 @@ public class VcnTest { } } + @Test + public void testContentObserverRegistered() { + // Validate state from setUp() + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + verify(mContentResolver) + .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); + } + + @Test + public void testMobileDataStateCheckedOnInitialization_enabled() { + // Validate state from setUp() + assertTrue(mVcn.isMobileDataEnabled()); + verify(mTelephonyManager).isDataEnabled(); + } + + @Test + public void testMobileDataStateCheckedOnInitialization_disabled() { + // Build and setup new telephonyManager to ensure method call count is reset. + final TelephonyManager telephonyManager = + setupAndGetTelephonyManager(false /* isMobileDataEnabled */); + final Vcn vcn = + new Vcn( + mVcnContext, + TEST_SUB_GROUP, + mConfig, + mSubscriptionSnapshot, + mVcnCallback, + mDeps); + + assertFalse(vcn.isMobileDataEnabled()); + verify(mTelephonyManager).isDataEnabled(); + } + @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE); @@ -193,7 +264,8 @@ public class VcnTest { eq(TEST_SUB_GROUP), eq(mSubscriptionSnapshot), any(), - mGatewayStatusCallbackCaptor.capture()); + mGatewayStatusCallbackCaptor.capture(), + eq(MOBILE_DATA_ENABLED)); return gatewayConnections; } @@ -256,20 +328,21 @@ public class VcnTest { mTestLooper.dispatchAll(); // Verify that the VCN requests the networkRequests be resent - assertEquals(1, mVcn.getVcnGatewayConnections().size()); + assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size()); verify(mVcnNetworkProvider).resendAllRequests(requestListener); // Verify that the VcnGatewayConnection is restarted if a request exists for it triggerVcnRequestListeners(requestListener); mTestLooper.dispatchAll(); - assertEquals(2, mVcn.getVcnGatewayConnections().size()); + assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size()); verify(mDeps, times(gatewayConnections.size() + 1)) .newVcnGatewayConnection( eq(mVcnContext), eq(TEST_SUB_GROUP), eq(mSubscriptionSnapshot), any(), - mGatewayStatusCallbackCaptor.capture()); + mGatewayStatusCallbackCaptor.capture(), + anyBoolean()); } @Test @@ -286,7 +359,7 @@ public class VcnTest { public void testUpdateConfigReevaluatesGatewayConnections() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startGatewaysAndGetGatewayConnections(requestListener); - assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size()); + assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size()); // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name @@ -309,4 +382,57 @@ public class VcnTest { verify(removedGatewayConnection).teardownAsynchronously(); verify(mVcnNetworkProvider).resendAllRequests(requestListener); } + + private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + // Start VcnGatewayConnections + mVcn.setMobileDataEnabled(startingToggleState); + triggerVcnRequestListeners(verifyAndGetRequestListener()); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); + + // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the + // toggle state changed. + for (Entry entry : gateways.entrySet()) { + final Set exposedCaps = entry.getKey().getAllExposedCapabilities(); + if (startingToggleState != endingToggleState + && (exposedCaps.contains(NET_CAPABILITY_INTERNET) + || exposedCaps.contains(NET_CAPABILITY_DUN))) { + verify(entry.getValue()).teardownAsynchronously(); + } else { + verify(entry.getValue(), never()).teardownAsynchronously(); + } + } + + assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); + } + + @Test + public void testMobileDataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); + } + + @Test + public void testMobileDataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + } } From 280cfc6943bafe22922caecc8400530e836ecd3d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 14:41:01 -0700 Subject: [PATCH 0186/1057] Improve dump detail This change improves the formatting and detail provided by the VCN dump Bug: 8675309 Test: atest FrameworksVcnTests Merged-In: I8f13a0d8fe54e9bf8948e9576e9705024fe79611 Change-Id: I8f13a0d8fe54e9bf8948e9576e9705024fe79611 (cherry picked from commit 7b811fcee8cd5b0df80cb3d44fa47d7ca55aad5b) --- .../android/server/VcnManagementService.java | 36 +++++++++++++++++++ .../vcn/TelephonySubscriptionTracker.java | 12 +++++++ .../server/vcn/UnderlyingNetworkTracker.java | 13 +++++++ .../server/vcn/VcnGatewayConnection.java | 6 ++++ .../server/vcn/VcnNetworkProvider.java | 4 +++ 5 files changed, 71 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 9c10658e7c..45717f200c 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -936,13 +936,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.println("VcnManagementService dump:"); pw.increaseIndent(); + pw.println("mNetworkProvider:"); + pw.increaseIndent(); mNetworkProvider.dump(pw); + pw.decreaseIndent(); + pw.println(); + + pw.println("mTrackingNetworkCallback:"); + pw.increaseIndent(); + mTrackingNetworkCallback.dump(pw); + pw.decreaseIndent(); + pw.println(); synchronized (mLock) { + pw.println("mLastSnapshot:"); + pw.increaseIndent(); + mLastSnapshot.dump(pw); + pw.decreaseIndent(); + pw.println(); + pw.println("mVcns:"); + pw.increaseIndent(); for (Vcn vcn : mVcns.values()) { vcn.dump(pw); } + pw.decreaseIndent(); pw.println(); } @@ -1004,6 +1022,24 @@ public class VcnManagementService extends IVcnManagementService.Stub { return false; } + + /** Dumps the state of this snapshot for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("TrackingNetworkCallback:"); + pw.increaseIndent(); + + pw.println("mCaps:"); + pw.increaseIndent(); + synchronized (mCaps) { + for (Entry entry : mCaps.entrySet()) { + pw.println(entry.getKey() + ": " + entry.getValue()); + } + } + pw.decreaseIndent(); + pw.println(); + + pw.decreaseIndent(); + } } /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index d8a145d9ae..19fbdbd860 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -43,6 +43,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import java.util.Collections; import java.util.HashMap; @@ -320,6 +321,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { && mPrivilegedPackages.equals(other.mPrivilegedPackages); } + /** Dumps the state of this snapshot for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("TelephonySubscriptionSnapshot:"); + pw.increaseIndent(); + + pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap); + pw.println("mPrivilegedPackages: " + mPrivilegedPackages); + + pw.decreaseIndent(); + } + @Override public String toString() { return "TelephonySubscriptionSnapshot{ " diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ab214e8329..48ccad33e6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -31,6 +31,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.ArrayList; @@ -396,6 +397,18 @@ public class UnderlyingNetworkTracker { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } + /** Dumps the state of this record for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkRecord:"); + pw.increaseIndent(); + + pw.println("mNetwork: " + network); + pw.println("mNetworkCapabilities: " + networkCapabilities); + pw.println("mLinkProperties: " + linkProperties); + + pw.decreaseIndent(); + } + /** Builder to incrementally construct an UnderlyingNetworkRecord. */ private static class Builder { @NonNull private final Network mNetwork; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8847dda71c..d8a085b092 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2054,6 +2054,12 @@ public class VcnGatewayConnection extends StateMachine { "mNetworkAgent.getNetwork(): " + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + pw.println("mUnderlying:"); + pw.increaseIndent(); + mUnderlying.dump(pw); + pw.decreaseIndent(); + pw.println(); + pw.decreaseIndent(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index be0deb57ee..4de0fdaba6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -163,15 +163,19 @@ public class VcnNetworkProvider extends NetworkProvider { pw.increaseIndent(); pw.println("mListeners:"); + pw.increaseIndent(); for (NetworkRequestListener listener : mListeners) { pw.println(listener); } + pw.decreaseIndent(); pw.println(); pw.println("mRequests.values:"); + pw.increaseIndent(); for (NetworkRequestEntry entry : mRequests.values()) { entry.dump(pw); } + pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); From 072ae41211559377cffdb0597f23cc60b3e16382 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 23:18:27 -0700 Subject: [PATCH 0187/1057] Remove use of network scores, and provider IDs in VcnNetworkProvider This change updates the VcnNetworkProvider and associated requestListeners to no longer use the network score and provider IDs, in order to match the new NetworkProvider APIs. Bug: 185204197 Test: atest FrameworksVcnTests Merged-In: I0cabce702cfd8457fd1a152af07a847b87d67028 Change-Id: I0cabce702cfd8457fd1a152af07a847b87d67028 (cherry picked from commit 4a15035b66bc495974b878b2498aa2cc579d1d16) --- .../src/com/android/server/vcn/Vcn.java | 24 ++----- .../server/vcn/VcnNetworkProvider.java | 66 ++++--------------- .../server/vcn/VcnNetworkProviderTest.java | 41 ++++++++---- .../java/com/android/server/vcn/VcnTest.java | 4 +- 4 files changed, 47 insertions(+), 88 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 70a8a7ff7b..c7c538521d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -265,10 +265,10 @@ public class Vcn extends Handler { private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + public void onNetworkRequested(@NonNull NetworkRequest request) { Objects.requireNonNull(request, "Missing request"); - sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request)); + sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, request)); } } @@ -284,7 +284,7 @@ public class Vcn extends Handler { handleConfigUpdated((VcnConfig) msg.obj); break; case MSG_EVENT_NETWORK_REQUESTED: - handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + handleNetworkRequested((NetworkRequest) msg.obj); break; case MSG_EVENT_SUBSCRIPTIONS_CHANGED: handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); @@ -365,25 +365,9 @@ public class Vcn extends Handler { } } - private void handleNetworkRequested( - @NonNull NetworkRequest request, int score, int providerId) { + private void handleNetworkRequested(@NonNull NetworkRequest request) { Slog.v(getLogTag(), "Received request " + request); - if (score > getNetworkScore()) { - if (VDBG) { - Slog.v( - getLogTag(), - "Request already satisfied by higher-scoring (" - + score - + ") network from " - + "provider " - + providerId - + ": " - + request); - } - return; - } - // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 4de0fdaba6..8adcf95e78 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -23,7 +23,6 @@ import android.content.Context; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.os.Looper; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -31,7 +30,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import java.util.Objects; import java.util.Set; /** @@ -48,11 +46,11 @@ public class VcnNetworkProvider extends NetworkProvider { private final Set mListeners = new ArraySet<>(); /** - * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest + * Cache of NetworkRequest(s). * *

      NetworkRequests are immutable once created, and therefore can be used as stable keys. */ - private final ArrayMap mRequests = new ArrayMap<>(); + private final Set mRequests = new ArraySet<>(); public VcnNetworkProvider(Context context, Looper looper) { super(context, looper, VcnNetworkProvider.class.getSimpleName()); @@ -80,38 +78,28 @@ public class VcnNetworkProvider extends NetworkProvider { /** Sends all cached NetworkRequest(s) to the specified listener. */ @VisibleForTesting(visibility = Visibility.PACKAGE) public void resendAllRequests(@NonNull NetworkRequestListener listener) { - for (NetworkRequestEntry entry : mRequests.values()) { - notifyListenerForEvent(listener, entry); + for (NetworkRequest request : mRequests) { + notifyListenerForEvent(listener, request); } } private void notifyListenerForEvent( - @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { - listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); + @NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) { + listener.onNetworkRequested(request); } @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { if (VDBG) { - Slog.v( - TAG, - "Network requested: Request = " - + request - + ", score = " - + score - + ", providerId = " - + providerId); + Slog.v(TAG, "Network requested: Request = " + request); } - final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId); - - // NetworkRequests are immutable once created, and therefore can be used as stable keys. - mRequests.put(request, entry); + mRequests.add(request); // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on // Default Data Sub, or similar) for (NetworkRequestListener listener : mListeners) { - notifyListenerForEvent(listener, entry); + notifyListenerForEvent(listener, request); } } @@ -120,37 +108,9 @@ public class VcnNetworkProvider extends NetworkProvider { mRequests.remove(request); } - private static class NetworkRequestEntry { - public final NetworkRequest mRequest; - public final int mScore; - public final int mProviderId; - - private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) { - mRequest = Objects.requireNonNull(request, "Missing request"); - mScore = score; - mProviderId = providerId; - } - - /** - * Dumps the state of this NetworkRequestEntry for logging and debugging purposes. - * - *

      PII and credentials MUST NEVER be dumped here. - */ - public void dump(IndentingPrintWriter pw) { - pw.println("NetworkRequestEntry:"); - pw.increaseIndent(); - - pw.println("mRequest: " + mRequest); - pw.println("mScore: " + mScore); - pw.println("mProviderId: " + mProviderId); - - pw.decreaseIndent(); - } - } - // package-private interface NetworkRequestListener { - void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId); + void onNetworkRequested(@NonNull NetworkRequest request); } /** @@ -170,10 +130,10 @@ public class VcnNetworkProvider extends NetworkProvider { pw.decreaseIndent(); pw.println(); - pw.println("mRequests.values:"); + pw.println("mRequests:"); pw.increaseIndent(); - for (NetworkRequestEntry entry : mRequests.values()) { - entry.dump(pw); + for (NetworkRequest request : mRequests) { + pw.println(request); } pw.decreaseIndent(); pw.println(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index f943f34c9d..79cf746f10 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -34,12 +34,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.List; + /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @SmallTest public class VcnNetworkProviderTest { private static final int TEST_SCORE_UNSATISFIED = 0; - private static final int TEST_SCORE_HIGH = 100; private static final int TEST_PROVIDER_ID = 1; @NonNull private final Context mContext; @@ -65,17 +67,7 @@ public class VcnNetworkProviderTest { final NetworkRequest request = mock(NetworkRequest.class); mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); - verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); - } - - @Test - public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider() - throws Exception { - mVcnNetworkProvider.registerListener(mListener); - - final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); - verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID); + verify(mListener).onNetworkRequested(request); } @Test @@ -87,4 +79,29 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); verifyNoMoreInteractions(mListener); } + + @Test + public void testCachedRequestsPassedOnRegister() throws Exception { + final List requests = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + // Build unique network requests; in this case, iterate down the capabilities as a way + // to unique-ify requests. + final NetworkRequest request = + new NetworkRequest.Builder().clearCapabilities().addCapability(i).build(); + + requests.add(request); + mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); + } + + // Remove one, and verify that it is never sent to the listeners. + final NetworkRequest removed = requests.remove(0); + mVcnNetworkProvider.onNetworkRequestWithdrawn(removed); + + mVcnNetworkProvider.registerListener(mListener); + for (NetworkRequest request : requests) { + verify(mListener).onNetworkRequested(request); + } + verifyNoMoreInteractions(mListener); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 7c2a5a1cfc..736fabdb1a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -75,8 +75,6 @@ import java.util.UUID; public class VcnTest { private static final String PKG_NAME = VcnTest.class.getPackage().getName(); private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); - private static final int NETWORK_SCORE = 0; - private static final int PROVIDER_ID = 5; private static final boolean MOBILE_DATA_ENABLED = true; private static final Set TEST_SUB_IDS_IN_GROUP = new ArraySet<>(Arrays.asList(1, 2, 3)); @@ -177,7 +175,7 @@ public class VcnTest { requestBuilder.addCapability(netCapability); } - requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID); + requestListener.onNetworkRequested(requestBuilder.build()); mTestLooper.dispatchAll(); } From 8dcd0066c3dc6563fd03875d1bb3c3ca3946b75b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 12 Apr 2021 23:42:59 -0700 Subject: [PATCH 0188/1057] Switch to using NetworkScore instead of legacy integer This change switches the VcnNetworkAgent from using the legacy score integer, and switches to using the new NetworkScore, using the legacy integer as a internal representation. Bug: 185204197 Test: FrameworksVcnTests Merged-In: Ib0690243f176a2f074358fcc8430f1fd7c3d0d3c Change-Id: Ib0690243f176a2f074358fcc8430f1fd7c3d0d3c (cherry picked from commit 13610319a30478f1e76de9744c462a4d604c3e8d) --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 11 ++++++----- .../com/android/server/vcn/VcnGatewayConnection.java | 5 +++-- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 10 +++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index c7c538521d..cccb0968fc 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -32,6 +32,7 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; @@ -71,6 +72,8 @@ import java.util.Set; public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); + private static final int VCN_LEGACY_SCORE_INT = 52; + private static final List CAPS_REQUIRING_MOBILE_DATA = Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); @@ -527,11 +530,9 @@ public class Vcn extends Handler { } /** Retrieves the network score for a VCN Network */ - // Package visibility for use in VcnGatewayConnection - static int getNetworkScore() { - // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in - // subGrp" value - return 52; + // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider + static NetworkScore getNetworkScore() { + return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build(); } /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index d8a085b092..38f5dd6c3a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -49,6 +49,7 @@ import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; +import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; @@ -2203,7 +2204,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull String tag, @NonNull NetworkCapabilities caps, @NonNull LinkProperties lp, - @NonNull int score, + @NonNull NetworkScore score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, @NonNull Consumer networkUnwantedCallback, @@ -2344,7 +2345,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull String tag, @NonNull NetworkCapabilities caps, @NonNull LinkProperties lp, - @NonNull int score, + @NonNull NetworkScore score, @NonNull NetworkAgentConfig nac, @NonNull NetworkProvider provider, @NonNull Consumer networkUnwantedCallback, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index a2223e8c1e..95a972652b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mNetworkAgent = mock(VcnNetworkAgent.class); doReturn(mNetworkAgent) .when(mDeps) - .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any()); + .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any()); mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); @@ -216,7 +216,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any(), any(), - anyInt(), + any(), any(), any(), any(), @@ -244,7 +244,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(String.class), ncCaptor.capture(), lpCaptor.capture(), - anyInt(), + any(), argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE), any(), any(), @@ -297,7 +297,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection startingInternalAddrs.equals(lp.getLinkAddresses()) && Collections.singletonList(TEST_DNS_ADDR) .equals(lp.getDnsServers())), - anyInt(), + any(), any(), any(), any(), @@ -356,7 +356,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any(), any(), - anyInt(), + any(), any(), any(), unwantedCallbackCaptor.capture(), From 1b817cdde6ea503d224685eea69e0629d47b499e Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 19 Apr 2021 19:43:04 -0700 Subject: [PATCH 0189/1057] Remove deprecated IKEv2 methods. This CL updates VcnManagerTest to: - not set a Context when creating IkeSessionParms for a VcnConfig - not require an active Network when creating IkeSessionParams Bug: 180521384 Bug: 185864339 Test: atest CtsVcnTestCases Change-Id: I22928b7808a9be2f3a2192d2a9992307f01444b2 --- .../src/android/net/vcn/cts/VcnManagerTest.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 107ae44134..9f72d0b875 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -24,7 +24,6 @@ import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; @@ -104,10 +103,8 @@ public class VcnManagerTest { final String testRemoteId = "test.server.com"; final byte[] psk = "psk".getBytes(); - // TODO: b/180521384: Build the IkeSessionParams without a Context when the no-arg - // IkeSessionParams.Builder constructor is exposed. final IkeSessionParams ikeParams = - new IkeSessionParams.Builder(mContext) + new IkeSessionParams.Builder() .setServerHostname(serverHostname) .addSaProposal(ikeProposal) .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) @@ -146,23 +143,11 @@ public class VcnManagerTest { @Test(expected = SecurityException.class) public void testSetVcnConfig_noCarrierPrivileges() throws Exception { - // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not - // require an active default network. - assertNotNull( - "You must have an active network connection to complete CTS", - mConnectivityManager.getActiveNetwork()); - mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig()); } @Test public void testSetVcnConfig_withCarrierPrivileges() throws Exception { - // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not - // require an active default network. - assertNotNull( - "You must have an active network connection to complete CTS", - mConnectivityManager.getActiveNetwork()); - final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { From a44fa1e0db9ed8bf495deb43609f3ca78f5b441d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 19 Apr 2021 15:21:46 -0700 Subject: [PATCH 0190/1057] Fix NPE in dump and add additional dump data This change fixes a NPE when the VcnGatwayConnection attempts to print for a null underlying network. Additionally, it also prints the existing configs in order to better identify whether a VCN config is failing to be privisoned, or failing to start. Test: manual testing Change-Id: I44d65633364a5f16d75519cead6729969eb1c06f --- .../src/com/android/server/VcnManagementService.java | 8 ++++++++ .../com/android/server/vcn/VcnGatewayConnection.java | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 45717f200c..6eb6a0ed7b 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -955,6 +955,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.decreaseIndent(); pw.println(); + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); + pw.println("mVcns:"); pw.increaseIndent(); for (Vcn vcn : mVcns.values()) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 38f5dd6c3a..77bfc5f461 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2046,7 +2046,11 @@ public class VcnGatewayConnection extends StateMachine { pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):"); pw.increaseIndent(); - pw.println("Current state: " + getCurrentState().getClass().getSimpleName()); + pw.println( + "Current state: " + + (getCurrentState() == null + ? null + : getCurrentState().getClass().getSimpleName())); pw.println("mIsQuitting: " + mIsQuitting); pw.println("mIsInSafeMode: " + mIsInSafeMode); pw.println("mCurrentToken: " + mCurrentToken); @@ -2057,7 +2061,11 @@ public class VcnGatewayConnection extends StateMachine { pw.println("mUnderlying:"); pw.increaseIndent(); - mUnderlying.dump(pw); + if (mUnderlying != null) { + mUnderlying.dump(pw); + } else { + pw.println("null"); + } pw.decreaseIndent(); pw.println(); From 39a9518be4695baa621e507845d85ef9c0d78f34 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 20 Apr 2021 14:43:16 -0700 Subject: [PATCH 0191/1057] Include PORT_4500 option when encoding IkeSessionParams This commit makes sure IKE_OPTION_FORCE_PORT_4500 is included when converting IkeSessionParams to a PersistableBundle. Bug: 185637142 Test: atest IkeSessionParamsUtilsTest Change-Id: I1fcd6d26e64217091ad960a1c51659046e70a6ac --- .../net/vcn/persistablebundleutils/IkeSessionParamsUtils.java | 3 +++ .../vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 9d3462cb0b..74d4c3b032 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -78,6 +78,7 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); } /** Serializes an IkeSessionParams to a PersistableBundle. */ @@ -124,6 +125,8 @@ public final class IkeSessionParamsUtils { result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); + // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new + // IKE_OPTION is defined in IKE module and added in the IkeSessionParams final List enabledIkeOptions = new ArrayList<>(); for (int option : IKE_OPTIONS) { if (params.hasIkeOption(option)) { diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 546d957d41..4226e64589 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -55,11 +55,13 @@ public class IkeSessionParamsUtilsTest { private static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); + // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated. return new IkeSessionParams.Builder() .setServerHostname(serverAddress.getHostAddress()) .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal()) .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) + .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .setAuthPsk("psk".getBytes()); } From 7bba2d696a3b30a4a9a5eb696b91ad6d02df8251 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 20 Apr 2021 17:34:02 -0700 Subject: [PATCH 0192/1057] Update usages to setRetryIntervalsMs() Bug: 184612525 Test: atest CtsVcnTestCases Change-Id: Ifcd226d0ffb17449db60de3a91460e1c4acb9b15 --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 107ae44134..09c49a6f88 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -130,7 +130,7 @@ public class VcnManagerTest { new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, controlConfig) .addExposedCapability(NET_CAPABILITY_INTERNET) .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) - .setRetryInterval( + .setRetryIntervalsMs( new long[] { TimeUnit.SECONDS.toMillis(1), TimeUnit.MINUTES.toMillis(1), From 1b4cc3e120947e4b918157840d9a1b8f344a93d3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 20 Apr 2021 15:12:13 -0700 Subject: [PATCH 0193/1057] Rename get/setRetryInterval to get/setRetryIntervalsMs Per API feedback, the get/set methods for retry intervals are renamed to be plural, and have time units Bug: 184612525 Test: atest FrameworksVcnTests Test: atest CtsVcnTestCases Change-Id: I51b3ffcfa44f72805f359e56b263da2558325372 --- .../net/vcn/VcnGatewayConnectionConfig.java | 22 ++++--------------- .../vcn/VcnGatewayConnectionConfigTest.java | 6 ++--- ...atewayConnectionRetryTimeoutStateTest.java | 2 +- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 75db3820f5..649e75e612 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -134,7 +134,7 @@ public final class VcnGatewayConnectionConfig { *

      To ensure the device is not constantly being woken up, this retry interval MUST be greater * than this value. * - * @see {@link Builder#setRetryInterval()} + * @see {@link Builder#setRetryIntervalsMs()} */ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); @@ -333,25 +333,11 @@ public final class VcnGatewayConnectionConfig { /** * Retrieves the configured retry intervals. * - * @see Builder#setRetryInterval(long[]) + * @see Builder#setRetryIntervalsMs(long[]) */ @NonNull - public long[] getRetryInterval() { - return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); - } - - /** - * Retrieves the configured retry intervals. - * - *

      Left to prevent the need to make major changes while changes are actively in flight. - * - * @deprecated use getRetryInterval() instead - * @hide - */ - @Deprecated - @NonNull public long[] getRetryIntervalsMs() { - return getRetryInterval(); + return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } /** @@ -559,7 +545,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnManager for additional discussion on fail-safe mode */ @NonNull - public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { + public Builder setRetryIntervalsMs(@NonNull long[] retryIntervalsMs) { validateRetryInterval(retryIntervalsMs); mRetryIntervalsMs = retryIntervalsMs; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 4ee4d611e9..db00670c9b 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -81,7 +81,7 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryInterval(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + newBuilder().setRetryIntervalsMs(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -133,7 +133,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullRetryInterval() { try { - newBuilder().setRetryInterval(null); + newBuilder().setRetryIntervalsMs(null); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -142,7 +142,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyRetryInterval() { try { - newBuilder().setRetryInterval(new long[0]); + newBuilder().setRetryIntervalsMs(new long[0]); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 6dbf7d552b..044bef5b00 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -38,7 +38,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void setUp() throws Exception { super.setUp(); - mFirstRetryInterval = mConfig.getRetryInterval()[0]; + mFirstRetryInterval = mConfig.getRetryIntervalsMs()[0]; mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); From afd1bbbf3fb8d262295eb7c3d20d85d235c85ea2 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 12 Apr 2021 10:09:53 -0700 Subject: [PATCH 0194/1057] Check for valid subId in VCN CTS tests. This CL updates VcnManagerTest CTS to verify that the subId used in testing is a valid subId (that it's not SubscriptionManager#INVALID_SUBSCRIPTION_ID). Bug: 184829049 Test: atest CtsVcnTestCases Change-Id: Id6294310a5f9ac1f35bf26c72c1a6c5ced50ae4a --- .../android/net/vcn/cts/VcnManagerTest.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 91a3c806c8..110351bfb6 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -21,9 +21,11 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; @@ -141,6 +143,15 @@ public class VcnManagerTest { .build(); } + private int verifyAndGetValidDataSubId() { + final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + assertNotEquals( + "There must be an active data subscription to complete CTS", + INVALID_SUBSCRIPTION_ID, + dataSubId); + return dataSubId; + } + @Test(expected = SecurityException.class) public void testSetVcnConfig_noCarrierPrivileges() throws Exception { mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig()); @@ -148,7 +159,7 @@ public class VcnManagerTest { @Test public void testSetVcnConfig_withCarrierPrivileges() throws Exception { - final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + final int dataSubId = verifyAndGetValidDataSubId(); CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); @@ -165,7 +176,8 @@ public class VcnManagerTest { @Test public void testClearVcnConfig_withCarrierPrivileges() throws Exception { - final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + final int dataSubId = verifyAndGetValidDataSubId(); + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { mVcnManager.clearVcnConfig(subGrp); @@ -271,7 +283,7 @@ public class VcnManagerTest { @Test public void testRegisterVcnStatusCallback() throws Exception { final TestVcnStatusCallback callback = new TestVcnStatusCallback(); - final int subId = SubscriptionManager.getDefaultSubscriptionId(); + final int subId = verifyAndGetValidDataSubId(); try { registerVcnStatusCallbackForSubId(callback, subId); @@ -286,7 +298,7 @@ public class VcnManagerTest { @Test public void testRegisterVcnStatusCallback_reuseUnregisteredCallback() throws Exception { final TestVcnStatusCallback callback = new TestVcnStatusCallback(); - final int subId = SubscriptionManager.getDefaultSubscriptionId(); + final int subId = verifyAndGetValidDataSubId(); try { registerVcnStatusCallbackForSubId(callback, subId); @@ -300,7 +312,7 @@ public class VcnManagerTest { @Test(expected = IllegalStateException.class) public void testRegisterVcnStatusCallback_duplicateRegister() throws Exception { final TestVcnStatusCallback callback = new TestVcnStatusCallback(); - final int subId = SubscriptionManager.getDefaultSubscriptionId(); + final int subId = verifyAndGetValidDataSubId(); try { registerVcnStatusCallbackForSubId(callback, subId); From d49b9a153d6853fdeef5b5e2537e35d311c884ad Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 20 Apr 2021 15:09:43 -0700 Subject: [PATCH 0195/1057] Add support for retrieval of configured VCNs by carrier privilege This change adds support for retrieval of a list of subscription groups that have a VCN configured. Bug: 184612525 Test: atest FrameworksVcnTests Change-Id: I40553a7bb45d9b1f948c7d0a791f1b22a422d55c --- .../net/vcn/IVcnManagementService.aidl | 3 ++ .../src/android/net/vcn/VcnManager.java | 19 ++++++++++ .../android/server/VcnManagementService.java | 28 ++++++++++++++ .../server/VcnManagementServiceTest.java | 38 +++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl index 5b79f7311b..e16f6b1677 100644 --- a/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl +++ b/Vcn/framework-b/src/android/net/vcn/IVcnManagementService.aidl @@ -24,12 +24,15 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.ParcelUuid; +import java.util.List; + /** * @hide */ interface IVcnManagementService { void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); void clearVcnConfig(in ParcelUuid subscriptionGroup, in String opPkgName); + List getConfiguredSubscriptionGroups(in String opPkgName); void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 344b20c036..1cd4ff0a5c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -38,6 +38,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -162,6 +163,24 @@ public class VcnManager { } } + /** + * Retrieves the list of Subscription Groups for which a VCN Configuration has been set. + * + *

      The returned list will include only subscription groups for which the carrier app is + * privileged, and which have an associated {@link VcnConfig}. + * + * @throws SecurityException if the caller is not running as the primary user + * @hide + */ + @NonNull + public List getConfiguredSubscriptionGroups() { + try { + return mService.getConfiguredSubscriptionGroups(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using // the new VcnNetworkPolicyChangeListener API /** diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 9c10658e7c..e1db241a6d 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -614,6 +614,34 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } + /** + * Retrieves the list of subscription groups with configured VcnConfigs + * + *

      Limited to subscription groups for which the caller is carrier privileged. + * + *

      Implements the IVcnManagementService Binder interface. + */ + @Override + @NonNull + public List getConfiguredSubscriptionGroups(@NonNull String opPkgName) { + requireNonNull(opPkgName, "opPkgName was null"); + + mContext.getSystemService(AppOpsManager.class) + .checkPackage(mDeps.getBinderCallingUid(), opPkgName); + enforcePrimaryUser(); + + final List result = new ArrayList<>(); + synchronized (mLock) { + for (ParcelUuid subGrp : mConfigs.keySet()) { + if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) { + result.add(subGrp); + } + } + } + + return result; + } + @GuardedBy("mLock") private void writeConfigsToDiskLocked() { try { diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index bbc9bb600f..38d2bb1c95 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -96,6 +96,7 @@ import org.mockito.ArgumentCaptor; import java.io.FileNotFoundException; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -616,6 +617,43 @@ public class VcnManagementServiceTest { verify(vcnInstance).teardownAsynchronously(); } + @Test + public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception { + doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) + .when(mMockDeps) + .getBinderCallingUid(); + + try { + mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); + fail("Expected security exception for non system user"); + } catch (SecurityException expected) { + } + } + + @Test + public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception { + final String badPackage = "IncorrectPackage"; + doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage); + + try { + mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage); + fail("Expected security exception due to mismatched packages"); + } catch (SecurityException expected) { + } + } + + @Test + public void testGetConfiguredSubscriptionGroups() throws Exception { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are + // privileged for. + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + final List subGrps = + mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); + assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); + } + @Test public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception { mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); From bb030739b234bd52d4589c6d81eca5522336c60b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 20 Apr 2021 15:14:31 -0700 Subject: [PATCH 0196/1057] Expose API for retrieval of subscription groups with VCN configured Per API council feedback, this change adds a new API to retrieve all subscription groups that have a VCN configured. Bug: 184612525 Test: atest FrameworksVcnTests Test: atest CtsVcnTestCases Change-Id: I64b565758e0a27552eee9f860e0674db2fb35980 --- Vcn/framework-b/src/android/net/vcn/VcnManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 1cd4ff0a5c..9d1c1ff898 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -170,7 +170,6 @@ public class VcnManager { * privileged, and which have an associated {@link VcnConfig}. * * @throws SecurityException if the caller is not running as the primary user - * @hide */ @NonNull public List getConfiguredSubscriptionGroups() { From 6d85b96458b0973d09754643860ef3ba4e770a7a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Mar 2021 11:20:31 -0700 Subject: [PATCH 0197/1057] Convert TunnelConnectionParams to/from PersistableBundle Add utility class to convert TunnelConnectionParams to and from PersistableBundle. Bug: 180664474 Test: atest EncryptedTunnelParamsUtilsTest Change-Id: I93ae068eb6d1e1c4d3fcbaccbaae867db8d07a38 --- .../TunnelConnectionParamsUtils.java | 106 ++++++++++++++++++ .../IkeSessionParamsUtilsTest.java | 3 +- .../TunnelConnectionParamsUtilsTest.java | 47 ++++++++ ...TunnelModeChildSessionParamsUtilsTest.java | 3 +- 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java new file mode 100644 index 0000000000..690e4e76ea --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java @@ -0,0 +1,106 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import android.annotation.NonNull; +import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.PersistableBundle; + +import java.util.Objects; + +/** + * Utility class to convert TunnelConnectionParams to/from PersistableBundle + * + * @hide + */ +public final class TunnelConnectionParamsUtils { + private static final int EXPECTED_BUNDLE_KEY_CNT = 1; + + private static final String PARAMS_TYPE_IKE = "IKE"; + + /** Serializes an TunnelConnectionParams to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) { + final PersistableBundle result = new PersistableBundle(); + + if (params instanceof IkeTunnelConnectionParams) { + result.putPersistableBundle( + PARAMS_TYPE_IKE, + IkeTunnelConnectionParamsUtils.serializeIkeParams( + (IkeTunnelConnectionParams) params)); + return result; + } else { + throw new UnsupportedOperationException("Invalid TunnelConnectionParams type"); + } + } + + /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */ + @NonNull + public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) { + throw new IllegalArgumentException( + "Expect PersistableBundle to have one element but found: " + in.keySet()); + } + + if (in.get(PARAMS_TYPE_IKE) != null) { + return IkeTunnelConnectionParamsUtils.deserializeIkeParams( + in.getPersistableBundle(PARAMS_TYPE_IKE)); + } + + throw new IllegalArgumentException( + "Invalid TunnelConnectionParams type " + in.keySet().iterator().next()); + } + + private static final class IkeTunnelConnectionParamsUtils { + private static final String IKE_PARAMS_KEY = "IKE_PARAMS_KEY"; + private static final String CHILD_PARAMS_KEY = "CHILD_PARAMS_KEY"; + + @NonNull + public static PersistableBundle serializeIkeParams( + @NonNull IkeTunnelConnectionParams ikeParams) { + final PersistableBundle result = new PersistableBundle(); + + result.putPersistableBundle( + IKE_PARAMS_KEY, + IkeSessionParamsUtils.toPersistableBundle(ikeParams.getIkeSessionParams())); + result.putPersistableBundle( + CHILD_PARAMS_KEY, + TunnelModeChildSessionParamsUtils.toPersistableBundle( + ikeParams.getTunnelModeChildSessionParams())); + return result; + } + + @NonNull + public static IkeTunnelConnectionParams deserializeIkeParams( + @NonNull PersistableBundle in) { + final PersistableBundle ikeBundle = in.getPersistableBundle(IKE_PARAMS_KEY); + final PersistableBundle childBundle = in.getPersistableBundle(CHILD_PARAMS_KEY); + Objects.requireNonNull(ikeBundle, "IkeSessionParams was null"); + Objects.requireNonNull(ikeBundle, "TunnelModeChildSessionParams was null"); + + final IkeSessionParams ikeParams = + IkeSessionParamsUtils.fromPersistableBundle(ikeBundle); + final TunnelModeChildSessionParams childParams = + TunnelModeChildSessionParamsUtils.fromPersistableBundle(childBundle); + return new IkeTunnelConnectionParams(ikeParams, childParams); + } + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 4226e64589..393787f1a8 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -52,7 +52,8 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IkeSessionParamsUtilsTest { - private static IkeSessionParams.Builder createBuilderMinimum() { + // Package private for use in EncryptedTunnelParamsUtilsTest + static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated. diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java new file mode 100644 index 0000000000..6a96cf1bd1 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java @@ -0,0 +1,47 @@ +/* + * 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 android.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeTunnelConnectionParams; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TunnelConnectionParamsUtilsTest { + private static IkeTunnelConnectionParams buildTestParams() { + return new IkeTunnelConnectionParams( + IkeSessionParamsUtilsTest.createBuilderMinimum().build(), + TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); + } + + @Test + public void testIkeTunnelConnectionParamsToFromPersistableBundle() { + final IkeTunnelConnectionParams params = buildTestParams(); + + assertEquals( + params, + TunnelConnectionParamsUtils.fromPersistableBundle( + TunnelConnectionParamsUtils.toPersistableBundle(params))); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java index b3cd0ab805..e0b5f0ef03 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java @@ -40,7 +40,8 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class TunnelModeChildSessionParamsUtilsTest { - private TunnelModeChildSessionParams.Builder createBuilderMinimum() { + // Package private for use in EncryptedTunnelParamsUtilsTest + static TunnelModeChildSessionParams.Builder createBuilderMinimum() { final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal(); return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal); } From 3b4400313db6ab574b51f3b4cdbafb7c8fb4a527 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 25 Mar 2021 16:06:30 -0700 Subject: [PATCH 0198/1057] Replace VcnControlPlaneConfig with TunnelConnectionParams Use the more generic object TunnelConnectionParams in VCN. TunnelConnectionParams may also be used in VPN in the future. Test: atest FrameworksVcnTests Bug: 180664474 Change-Id: Ie433f9df614e1f51cdff200d915b68b61e5ca35e --- .../net/vcn/VcnControlPlaneConfig.java | 112 ------------- .../net/vcn/VcnControlPlaneIkeConfig.java | 158 ------------------ .../net/vcn/VcnGatewayConnectionConfig.java | 47 +++--- .../server/vcn/VcnGatewayConnection.java | 46 +++-- .../net/vcn/VcnControlPlaneIkeConfigTest.java | 113 ------------- .../vcn/VcnGatewayConnectionConfigTest.java | 20 +-- .../TunnelConnectionParamsUtilsTest.java | 3 +- ...cnGatewayConnectionConnectedStateTest.java | 6 +- 8 files changed, 74 insertions(+), 431 deletions(-) delete mode 100644 Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java delete mode 100644 Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java delete mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java deleted file mode 100644 index 92f6c44403..0000000000 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneConfig.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 android.net.vcn; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.os.PersistableBundle; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Objects; - -/** - * This class represents a control plane configuration for a Virtual Carrier Network connection. - * - *

      Each {@link VcnGatewayConnectionConfig} must have a {@link VcnControlPlaneConfig}, containing - * all connection, authentication and authorization parameters required to establish a Gateway - * Connection with a remote endpoint. - * - *

      A {@link VcnControlPlaneConfig} object can be shared by multiple {@link - * VcnGatewayConnectionConfig}(s) if they will used for connecting with the same remote endpoint. - * - * @see VcnManager - * @see VcnGatewayConnectionConfig - */ -public abstract class VcnControlPlaneConfig { - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({CONFIG_TYPE_IKE}) - public @interface ConfigType {} - - /** @hide */ - public static final int CONFIG_TYPE_IKE = 1; - - private static final String CONFIG_TYPE_KEY = "mConfigType"; - @ConfigType private final int mConfigType; - - /** - * Package private constructor. - * - * @hide - */ - VcnControlPlaneConfig(int configType) { - mConfigType = configType; - } - - /** - * Constructs a VcnControlPlaneConfig object by deserializing a PersistableBundle. - * - * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneConfig} object - * @hide - */ - public static VcnControlPlaneConfig fromPersistableBundle(@NonNull PersistableBundle in) { - Objects.requireNonNull(in, "PersistableBundle was null"); - - int configType = in.getInt(CONFIG_TYPE_KEY); - switch (configType) { - case CONFIG_TYPE_IKE: - return new VcnControlPlaneIkeConfig(in); - default: - throw new IllegalStateException("Unrecognized configType: " + configType); - } - } - - /** - * Converts this VcnControlPlaneConfig to a PersistableBundle. - * - * @hide - */ - @NonNull - public PersistableBundle toPersistableBundle() { - final PersistableBundle result = new PersistableBundle(); - result.putInt(CONFIG_TYPE_KEY, mConfigType); - return result; - } - - /** @hide */ - @Override - public int hashCode() { - return Objects.hash(mConfigType); - } - - /** @hide */ - @Override - public boolean equals(Object o) { - if (!(o instanceof VcnControlPlaneConfig)) { - return false; - } - - return mConfigType == ((VcnControlPlaneConfig) o).mConfigType; - } - - /** - * Returns a deep copy of this object. - * - * @hide - */ - public abstract VcnControlPlaneConfig copy(); -} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java deleted file mode 100644 index 22d7faf2fe..0000000000 --- a/Vcn/framework-b/src/android/net/vcn/VcnControlPlaneIkeConfig.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 android.net.vcn; - -import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE; - -import android.annotation.NonNull; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; -import android.net.vcn.persistablebundleutils.IkeSessionParamsUtils; -import android.net.vcn.persistablebundleutils.TunnelModeChildSessionParamsUtils; -import android.os.PersistableBundle; -import android.util.ArraySet; -import android.util.Log; - -import java.util.Objects; - -/** - * This class is an IKEv2 control plane configuration for a Virtual Carrier Network connection. - * - *

      This class is an extension of the {@link VcnControlPlaneConfig}, containing IKEv2-specific - * configuration, authentication and authorization parameters. - * - * @see VcnControlPlaneConfig - */ -public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { - private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName(); - - private static final String IKE_PARAMS_KEY = "mIkeParams"; - @NonNull private final IkeSessionParams mIkeParams; - - private static final String CHILD_PARAMS_KEY = "mChildParams"; - @NonNull private final TunnelModeChildSessionParams mChildParams; - - private static final ArraySet BUNDLE_KEY_SET = new ArraySet<>(); - - { - BUNDLE_KEY_SET.add(IKE_PARAMS_KEY); - BUNDLE_KEY_SET.add(CHILD_PARAMS_KEY); - } - - /** - * Constructs a VcnControlPlaneIkeConfig object. - * - * @param ikeParams the IKE Session negotiation parameters - * @param childParams the tunnel mode Child Session negotiation parameters - */ - public VcnControlPlaneIkeConfig( - @NonNull IkeSessionParams ikeParams, - @NonNull TunnelModeChildSessionParams childParams) { - super(CONFIG_TYPE_IKE); - mIkeParams = ikeParams; - mChildParams = childParams; - validate(); - } - - /** - * Constructs a VcnControlPlaneIkeConfig object by deserializing a PersistableBundle. - * - * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneIkeConfig} object - * @hide - */ - public VcnControlPlaneIkeConfig(@NonNull PersistableBundle in) { - super(CONFIG_TYPE_IKE); - final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY); - final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY); - - Objects.requireNonNull(ikeParamsBundle, "IKE Session Params was null"); - Objects.requireNonNull(childParamsBundle, "Child Session Params was null"); - - mIkeParams = IkeSessionParamsUtils.fromPersistableBundle(ikeParamsBundle); - mChildParams = TunnelModeChildSessionParamsUtils.fromPersistableBundle(childParamsBundle); - - for (String key : in.keySet()) { - if (!BUNDLE_KEY_SET.contains(key)) { - Log.w(TAG, "Found an unexpected key in the PersistableBundle: " + key); - } - } - - validate(); - } - - private void validate() { - Objects.requireNonNull(mIkeParams, "mIkeParams was null"); - Objects.requireNonNull(mChildParams, "mChildParams was null"); - } - - /** - * Converts this VcnControlPlaneConfig to a PersistableBundle. - * - * @hide - */ - @Override - @NonNull - public PersistableBundle toPersistableBundle() { - final PersistableBundle result = super.toPersistableBundle(); - result.putPersistableBundle( - IKE_PARAMS_KEY, IkeSessionParamsUtils.toPersistableBundle(mIkeParams)); - result.putPersistableBundle( - CHILD_PARAMS_KEY, - TunnelModeChildSessionParamsUtils.toPersistableBundle(mChildParams)); - return result; - } - - /** Retrieves the IKE Session configuration. */ - @NonNull - public IkeSessionParams getIkeSessionParams() { - return mIkeParams; - } - - /** Retrieves the tunnel mode Child Session configuration. */ - @NonNull - public TunnelModeChildSessionParams getChildSessionParams() { - return mChildParams; - } - - /** @hide */ - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), mIkeParams, mChildParams); - } - - /** @hide */ - @Override - public boolean equals(Object o) { - if (!(o instanceof VcnControlPlaneIkeConfig)) { - return false; - } - - VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o; - - return super.equals(o) - && Objects.equals(mIkeParams, other.mIkeParams) - && Objects.equals(mChildParams, other.mChildParams); - } - - /** @hide */ - @Override - public VcnControlPlaneConfig copy() { - return new VcnControlPlaneIkeConfig( - new IkeSessionParams.Builder(mIkeParams).build(), - new TunnelModeChildSessionParams.Builder(mChildParams).build()); - } -} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 649e75e612..adcbe2542a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -24,6 +24,8 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.TunnelConnectionParams; +import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; @@ -151,8 +153,8 @@ public final class VcnGatewayConnectionConfig { private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName"; @NonNull private final String mGatewayConnectionName; - private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig"; - @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig; + private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; + @NonNull private TunnelConnectionParams mTunnelConnectionParams; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; @@ -169,13 +171,13 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, - @NonNull VcnControlPlaneConfig ctrlPlaneConfig, + @NonNull TunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; - mCtrlPlaneConfig = ctrlPlaneConfig; + mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; @@ -187,9 +189,10 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { - final PersistableBundle ctrlPlaneConfigBundle = - in.getPersistableBundle(CTRL_PLANE_CONFIG_KEY); - Objects.requireNonNull(ctrlPlaneConfigBundle, "ctrlPlaneConfigBundle was null"); + final PersistableBundle tunnelConnectionParamsBundle = + in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY); + Objects.requireNonNull( + tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null"); final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); @@ -197,7 +200,8 @@ public final class VcnGatewayConnectionConfig { in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); - mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle); + mTunnelConnectionParams = + TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( @@ -210,7 +214,7 @@ public final class VcnGatewayConnectionConfig { private void validate() { Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null"); - Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null"); + Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null"); Preconditions.checkArgument( mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), @@ -262,13 +266,13 @@ public final class VcnGatewayConnectionConfig { } /** - * Returns control plane configuration. + * Returns tunnel connection parameters. * * @hide */ @NonNull - public VcnControlPlaneConfig getControlPlaneConfig() { - return mCtrlPlaneConfig.copy(); + public TunnelConnectionParams getTunnelConnectionParams() { + return mTunnelConnectionParams; } /** @@ -360,7 +364,8 @@ public final class VcnGatewayConnectionConfig { public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); - final PersistableBundle ctrlPlaneConfigBundle = mCtrlPlaneConfig.toPersistableBundle(); + final PersistableBundle tunnelConnectionParamsBundle = + TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams); final PersistableBundle exposedCapsBundle = PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), @@ -371,7 +376,7 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); - result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle); + result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); @@ -409,7 +414,7 @@ public final class VcnGatewayConnectionConfig { */ public static final class Builder { @NonNull private final String mGatewayConnectionName; - @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig; + @NonNull private final TunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -427,18 +432,18 @@ public final class VcnGatewayConnectionConfig { * VcnConfig} must be given a unique name. This name is used by the caller to * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. - * @param ctrlPlaneConfig the control plane configuration - * @see VcnControlPlaneConfig + * @param tunnelConnectionParams the tunnel connection configuration + * @see TunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ public Builder( @NonNull String gatewayConnectionName, - @NonNull VcnControlPlaneConfig ctrlPlaneConfig) { + @NonNull TunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); - Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null"); + Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); mGatewayConnectionName = gatewayConnectionName; - mCtrlPlaneConfig = ctrlPlaneConfig; + mTunnelConnectionParams = tunnelConnectionParams; } /** @@ -583,7 +588,7 @@ public final class VcnGatewayConnectionConfig { public VcnGatewayConnectionConfig build() { return new VcnGatewayConnectionConfig( mGatewayConnectionName, - mCtrlPlaneConfig, + mTunnelConnectionParams, mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 77bfc5f461..6ca3c4b660 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -52,6 +52,7 @@ import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; +import android.net.TunnelConnectionParams; import android.net.Uri; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -61,10 +62,10 @@ import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; @@ -1923,8 +1924,14 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @Nullable UnderlyingNetworkRecord underlying) { - final VcnControlPlaneIkeConfig controlPlaneConfig = - (VcnControlPlaneIkeConfig) gatewayConnectionConfig.getControlPlaneConfig(); + final TunnelConnectionParams tunnelParams = + gatewayConnectionConfig.getTunnelConnectionParams(); + if (!(tunnelParams instanceof IkeTunnelConnectionParams)) { + throw new IllegalStateException( + "TunnelConnectionParams is not IkeTunnelConnectionParams"); + } + + final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams; final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -1943,7 +1950,7 @@ public class VcnGatewayConnection extends StateMachine { final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu(); lp.setMtu( MtuUtils.getMtu( - controlPlaneConfig.getChildSessionParams().getSaProposals(), + ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), gatewayConnectionConfig.getMaxMtu(), underlyingMtu)); @@ -2131,19 +2138,32 @@ public class VcnGatewayConnection extends StateMachine { } private IkeSessionParams buildIkeParams(@NonNull Network network) { - final VcnControlPlaneIkeConfig controlPlaneConfig = - (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); - final IkeSessionParams.Builder builder = - new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams()); - builder.setNetwork(network); + final TunnelConnectionParams tunnelConnectionParams = + mConnectionConfig.getTunnelConnectionParams(); - return builder.build(); + if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { + final IkeTunnelConnectionParams ikeTunnelConnectionParams = + (IkeTunnelConnectionParams) tunnelConnectionParams; + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); + builder.setNetwork(network); + + return builder.build(); + } + + throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); } private ChildSessionParams buildChildParams() { - final VcnControlPlaneIkeConfig controlPlaneConfig = - (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); - return controlPlaneConfig.getChildSessionParams(); + final TunnelConnectionParams tunnelConnectionParams = + mConnectionConfig.getTunnelConnectionParams(); + + if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { + return ((IkeTunnelConnectionParams) tunnelConnectionParams) + .getTunnelModeChildSessionParams(); + } + + throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java deleted file mode 100644 index 43b80e4c1b..0000000000 --- a/Vcn/tests/unit/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java +++ /dev/null @@ -1,113 +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.vcn; - -import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSaProposal; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.SaProposal; -import android.net.ipsec.ike.TunnelModeChildSessionParams; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class VcnControlPlaneIkeConfigTest { - private static final IkeSessionParams IKE_PARAMS; - private static final TunnelModeChildSessionParams CHILD_PARAMS; - - static { - IkeSaProposal ikeProposal = - new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) - .addDhGroup(DH_GROUP_2048_BIT_MODP) - .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) - .build(); - - final String serverHostname = "192.0.2.100"; - final String testLocalId = "test.client.com"; - final String testRemoteId = "test.server.com"; - final byte[] psk = "psk".getBytes(); - - IKE_PARAMS = - new IkeSessionParams.Builder() - .setServerHostname(serverHostname) - .addSaProposal(ikeProposal) - .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) - .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) - .setAuthPsk(psk) - .build(); - - ChildSaProposal childProposal = - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) - .build(); - CHILD_PARAMS = - new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); - } - - // Package private for use in VcnGatewayConnectionConfigTest - static VcnControlPlaneIkeConfig buildTestConfig() { - return new VcnControlPlaneIkeConfig(IKE_PARAMS, CHILD_PARAMS); - } - - @Test - public void testGetters() { - final VcnControlPlaneIkeConfig config = buildTestConfig(); - assertEquals(IKE_PARAMS, config.getIkeSessionParams()); - assertEquals(CHILD_PARAMS, config.getChildSessionParams()); - } - - @Test - public void testPersistableBundle() { - final VcnControlPlaneIkeConfig config = buildTestConfig(); - - assertEquals(config, new VcnControlPlaneIkeConfig(config.toPersistableBundle())); - } - - @Test - public void testConstructConfigWithoutIkeParams() { - try { - new VcnControlPlaneIkeConfig(null, CHILD_PARAMS); - fail("Expect to fail because ikeParams was null"); - } catch (NullPointerException expected) { - } - } - - @Test - public void testBuilderConfigWithoutChildParams() { - try { - new VcnControlPlaneIkeConfig(IKE_PARAMS, null); - fail("Expect to fail because childParams was null"); - } catch (NullPointerException expected) { - } - } -} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index db00670c9b..0d3fd3fef4 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -18,11 +18,12 @@ package android.net.vcn; 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.NetworkCapabilities; +import android.net.TunnelConnectionParams; +import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -59,8 +60,8 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; - public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG = - VcnControlPlaneIkeConfigTest.buildTestConfig(); + public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS = + TunnelConnectionParamsUtilsTest.buildTestParams(); public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; private static int sGatewayConnectionConfigCount = 0; @@ -75,7 +76,7 @@ public class VcnGatewayConnectionConfigTest { // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig). return new VcnGatewayConnectionConfig.Builder( GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++, - CONTROL_PLANE_CONFIG); + TUNNEL_CONNECTION_PARAMS); } // Public for use in VcnGatewayConnectionTest @@ -98,7 +99,7 @@ public class VcnGatewayConnectionConfigTest { public void testBuilderRequiresNonNullGatewayConnectionName() { try { new VcnGatewayConnectionConfig.Builder( - null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG) + null /* gatewayConnectionName */, TUNNEL_CONNECTION_PARAMS) .build(); fail("Expected exception due to invalid gateway connection name"); @@ -107,13 +108,13 @@ public class VcnGatewayConnectionConfigTest { } @Test - public void testBuilderRequiresNonNullControlPlaneConfig() { + public void testBuilderRequiresNonNullTunnelConnectionParams() { try { new VcnGatewayConnectionConfig.Builder( - GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */) + GATEWAY_CONNECTION_NAME_PREFIX, null /* tunnelConnectionParams */) .build(); - fail("Expected exception due to invalid control plane config"); + fail("Expected exception due to the absence of tunnel connection parameters"); } catch (NullPointerException e) { } } @@ -171,8 +172,7 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(underlyingCaps); assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); - assertEquals(CONTROL_PLANE_CONFIG, config.getControlPlaneConfig()); - assertFalse(CONTROL_PLANE_CONFIG == config.getControlPlaneConfig()); + assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); assertEquals(MAX_MTU, config.getMaxMtu()); diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java index 6a96cf1bd1..0c8ad32b0c 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java @@ -29,7 +29,8 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class TunnelConnectionParamsUtilsTest { - private static IkeTunnelConnectionParams buildTestParams() { + // Public for use in VcnGatewayConnectionConfigTest + public static IkeTunnelConnectionParams buildTestParams() { return new IkeTunnelConnectionParams( IkeSessionParamsUtilsTest.createBuilderMinimum().build(), TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 95a972652b..530e63699e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -51,10 +51,10 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; -import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnManager.VcnErrorCode; import androidx.test.filters.SmallTest; @@ -181,8 +181,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List saProposals = - ((VcnControlPlaneIkeConfig) mConfig.getControlPlaneConfig()) - .getChildSessionParams() + ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams()) + .getTunnelModeChildSessionParams() .getSaProposals(); final int expectedMtu = MtuUtils.getMtu( From 2924925c16d69608a0ff1842f33566062ca69217 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 25 Mar 2021 16:06:30 -0700 Subject: [PATCH 0199/1057] Remove TunnelConnectionParams interface To avoid exposing empty interface. Test: atest FrameworksVcnTests Bug: 180664474 Change-Id: Ia33e75b77f1563a1c3d31e0145b7ec2be728b6db --- .../net/vcn/VcnGatewayConnectionConfig.java | 16 ++++---- .../TunnelConnectionParamsUtils.java | 31 +++++++--------- .../server/vcn/VcnGatewayConnection.java | 37 ++++--------------- .../vcn/VcnGatewayConnectionConfigTest.java | 4 +- ...cnGatewayConnectionConnectedStateTest.java | 3 +- 5 files changed, 32 insertions(+), 59 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index adcbe2542a..85ac5efabb 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -24,7 +24,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; @@ -154,7 +154,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; - @NonNull private TunnelConnectionParams mTunnelConnectionParams; + @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; @@ -171,7 +171,7 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams, + @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @@ -271,7 +271,7 @@ public final class VcnGatewayConnectionConfig { * @hide */ @NonNull - public TunnelConnectionParams getTunnelConnectionParams() { + public IkeTunnelConnectionParams getTunnelConnectionParams() { return mTunnelConnectionParams; } @@ -414,7 +414,7 @@ public final class VcnGatewayConnectionConfig { */ public static final class Builder { @NonNull private final String mGatewayConnectionName; - @NonNull private final TunnelConnectionParams mTunnelConnectionParams; + @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -432,13 +432,13 @@ public final class VcnGatewayConnectionConfig { * VcnConfig} must be given a unique name. This name is used by the caller to * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. - * @param tunnelConnectionParams the tunnel connection configuration - * @see TunnelConnectionParams + * @param tunnelConnectionParams the IKE tunnel connection configuration + * @see IkeTunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ public Builder( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams) { + @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java index 690e4e76ea..4bc5b49aa2 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java @@ -16,7 +16,6 @@ package android.net.vcn.persistablebundleutils; import android.annotation.NonNull; -import android.net.TunnelConnectionParams; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; @@ -25,7 +24,7 @@ import android.os.PersistableBundle; import java.util.Objects; /** - * Utility class to convert TunnelConnectionParams to/from PersistableBundle + * Utility class to convert Tunnel Connection Params to/from PersistableBundle * * @hide */ @@ -34,30 +33,28 @@ public final class TunnelConnectionParamsUtils { private static final String PARAMS_TYPE_IKE = "IKE"; - /** Serializes an TunnelConnectionParams to a PersistableBundle. */ + /** Serializes an IkeTunnelConnectionParams to a PersistableBundle. */ @NonNull - public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) { + public static PersistableBundle toPersistableBundle(@NonNull IkeTunnelConnectionParams params) { final PersistableBundle result = new PersistableBundle(); - if (params instanceof IkeTunnelConnectionParams) { - result.putPersistableBundle( - PARAMS_TYPE_IKE, - IkeTunnelConnectionParamsUtils.serializeIkeParams( - (IkeTunnelConnectionParams) params)); - return result; - } else { - throw new UnsupportedOperationException("Invalid TunnelConnectionParams type"); - } + result.putPersistableBundle( + PARAMS_TYPE_IKE, + IkeTunnelConnectionParamsUtils.serializeIkeParams( + (IkeTunnelConnectionParams) params)); + return result; } - /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */ + /** Constructs an IkeTunnelConnectionParams by deserializing a PersistableBundle. */ @NonNull - public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { + public static IkeTunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) { throw new IllegalArgumentException( - "Expect PersistableBundle to have one element but found: " + in.keySet()); + String.format( + "Expect PersistableBundle to have %d element but found: %d", + EXPECTED_BUNDLE_KEY_CNT, in.keySet())); } if (in.get(PARAMS_TYPE_IKE) != null) { @@ -66,7 +63,7 @@ public final class TunnelConnectionParamsUtils { } throw new IllegalArgumentException( - "Invalid TunnelConnectionParams type " + in.keySet().iterator().next()); + "Invalid Tunnel Connection Params type " + in.keySet().iterator().next()); } private static final class IkeTunnelConnectionParamsUtils { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 6ca3c4b660..8f60b09c58 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -52,7 +52,6 @@ import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; -import android.net.TunnelConnectionParams; import android.net.Uri; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -1924,14 +1923,8 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @Nullable UnderlyingNetworkRecord underlying) { - final TunnelConnectionParams tunnelParams = + final IkeTunnelConnectionParams ikeTunnelParams = gatewayConnectionConfig.getTunnelConnectionParams(); - if (!(tunnelParams instanceof IkeTunnelConnectionParams)) { - throw new IllegalStateException( - "TunnelConnectionParams is not IkeTunnelConnectionParams"); - } - - final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams; final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -2138,32 +2131,16 @@ public class VcnGatewayConnection extends StateMachine { } private IkeSessionParams buildIkeParams(@NonNull Network network) { - final TunnelConnectionParams tunnelConnectionParams = + final IkeTunnelConnectionParams ikeTunnelConnectionParams = mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - final IkeTunnelConnectionParams ikeTunnelConnectionParams = - (IkeTunnelConnectionParams) tunnelConnectionParams; - final IkeSessionParams.Builder builder = - new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); - builder.setNetwork(network); - - return builder.build(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); + builder.setNetwork(network); + return builder.build(); } private ChildSessionParams buildChildParams() { - final TunnelConnectionParams tunnelConnectionParams = - mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - return ((IkeTunnelConnectionParams) tunnelConnectionParams) - .getTunnelModeChildSessionParams(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams(); } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 0d3fd3fef4..7cfd275639 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; import androidx.test.filters.SmallTest; @@ -60,7 +60,7 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; - public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS = + public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS = TunnelConnectionParamsUtilsTest.buildTestParams(); public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 530e63699e..90ee73866b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -51,7 +51,6 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -181,7 +180,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List saProposals = - ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams()) + mConfig.getTunnelConnectionParams() .getTunnelModeChildSessionParams() .getSaProposals(); final int expectedMtu = From 37c916b12f2911de1b1e1b018bcf9c23ea0bccb4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Apr 2021 14:52:36 -0700 Subject: [PATCH 0200/1057] Set safe mode alarm when validation reports NOT_VALID Bug: 186257328 Test: atest FrameworksVcnTests Change-Id: I80f37d42e4d61026b3521a4133257cd472c22f1a --- .../server/vcn/VcnGatewayConnection.java | 18 +++++++++++-- ...cnGatewayConnectionConnectedStateTest.java | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8f60b09c58..08a1b7ebab 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1558,8 +1558,22 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { - if (status == NetworkAgent.VALIDATION_STATUS_VALID) { - clearFailedAttemptCounterAndSafeModeAlarm(); + switch (status) { + case NetworkAgent.VALIDATION_STATUS_VALID: + clearFailedAttemptCounterAndSafeModeAlarm(); + break; + case NetworkAgent.VALIDATION_STATUS_NOT_VALID: + // Will only set a new alarm if no safe mode alarm is + // currently scheduled. + setSafeModeAlarm(); + break; + default: + Slog.wtf( + TAG, + "Unknown validation status " + + status + + "; ignoring"); + break; } } /* validationStatusCallback */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 90ee73866b..eedaac4829 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -343,6 +343,31 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } + @Test + public void testSubsequentFailedValidationTriggersSafeMode() throws Exception { + triggerChildOpened(); + mTestLooper.dispatchAll(); + + triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + assertFalse(mGatewayConnection.isInSafeMode()); + + // Trigger a failed validation, and the subsequent safemode timeout. + triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + mTestLooper.dispatchAll(); + + final ArgumentCaptor runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mDeps, times(2)) + .newWakeupMessage( + eq(mVcnContext), + any(), + eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM), + runnableCaptor.capture()); + runnableCaptor.getValue().run(); + mTestLooper.dispatchAll(); + + assertTrue(mGatewayConnection.isInSafeMode()); + } + private Consumer setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); From d47242785991cfd4259db1929af3c72b97af0213 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Apr 2021 11:57:06 -0700 Subject: [PATCH 0201/1057] Update set|getRetryIntervalsMs to Millis Bug: 184612525 Test: atest FrameworksVcnTests Change-Id: I696854960ca9488ae2c8a0c569c57a8563998ac8 --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 8 ++++---- .../src/com/android/server/vcn/VcnGatewayConnection.java | 2 +- .../android/net/vcn/VcnGatewayConnectionConfigTest.java | 8 ++++---- .../vcn/VcnGatewayConnectionRetryTimeoutStateTest.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 85ac5efabb..be308d01d9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -136,7 +136,7 @@ public final class VcnGatewayConnectionConfig { *

      To ensure the device is not constantly being woken up, this retry interval MUST be greater * than this value. * - * @see {@link Builder#setRetryIntervalsMs()} + * @see {@link Builder#setRetryIntervalsMillis()} */ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); @@ -337,10 +337,10 @@ public final class VcnGatewayConnectionConfig { /** * Retrieves the configured retry intervals. * - * @see Builder#setRetryIntervalsMs(long[]) + * @see Builder#setRetryIntervalsMillis(long[]) */ @NonNull - public long[] getRetryIntervalsMs() { + public long[] getRetryIntervalsMillis() { return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } @@ -550,7 +550,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnManager for additional discussion on fail-safe mode */ @NonNull - public Builder setRetryIntervalsMs(@NonNull long[] retryIntervalsMs) { + public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) { validateRetryInterval(retryIntervalsMs); mRetryIntervalsMs = retryIntervalsMs; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 8f60b09c58..dc2b576eff 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1837,7 +1837,7 @@ public class VcnGatewayConnection extends StateMachine { private long getNextRetryIntervalsMs() { final int retryDelayIndex = mFailedAttempts - 1; - final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs(); + final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMillis(); // Repeatedly use last item in retry timeout list. if (retryDelayIndex >= retryIntervalsMs.length) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 7cfd275639..9410886c35 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -82,7 +82,7 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryIntervalsMs(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -134,7 +134,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullRetryInterval() { try { - newBuilder().setRetryIntervalsMs(null); + newBuilder().setRetryIntervalsMillis(null); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -143,7 +143,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyRetryInterval() { try { - newBuilder().setRetryIntervalsMs(new long[0]); + newBuilder().setRetryIntervalsMillis(new long[0]); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -174,7 +174,7 @@ public class VcnGatewayConnectionConfigTest { assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); - assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 044bef5b00..a88f112f45 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -38,7 +38,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void setUp() throws Exception { super.setUp(); - mFirstRetryInterval = mConfig.getRetryIntervalsMs()[0]; + mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0]; mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); From 2f0ef6903dc669cf9e902ba7b6f0577c5da37b5c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 23 Apr 2021 16:01:28 -0700 Subject: [PATCH 0202/1057] Allow VcnTransportInfo to be parcelled Allows VCN transport info to be parcelled for purposes of sysUI Bug: 186025257 Test: atest FrameworksVcnTests Change-Id: I5a5d9b88659c8dcaa9ded16d491b2bac0529169a --- .../src/android/net/vcn/VcnTransportInfo.java | 100 +++++++++++++++--- .../android/net/vcn/VcnTransportInfoTest.java | 41 +++++++ 2 files changed, 129 insertions(+), 12 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 4d8cf91621..0e9ccf144c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -16,14 +16,23 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionManager; +import com.android.internal.annotations.VisibleForTesting; + import java.util.Objects; /** @@ -37,28 +46,41 @@ import java.util.Objects; * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo * will be {@code null}. * + *

      Receipt of a VcnTransportInfo requires the NETWORK_SETTINGS permission; else the entire + * VcnTransportInfo instance will be redacted. + * * @hide */ public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; + /** + * The redaction scheme to use when parcelling. + * + *

      The TransportInfo/NetworkCapabilities redaction mechanisms rely on redaction being + * performed at parcelling time. This means that the redaction scheme must be stored for later + * use. + * + *

      Since the redaction scheme itself is not parcelled, this field is listed as a transient. + * + *

      Defaults to REDACT_ALL when constructed using public constructors, or creating from + * parcels. + */ + private final transient long mRedactions; + public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + this(wifiInfo, INVALID_SUBSCRIPTION_ID, REDACT_ALL); } public VcnTransportInfo(int subId) { - this(null /* wifiInfo */, subId); + this(null /* wifiInfo */, subId, REDACT_ALL); } - private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { - if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - throw new IllegalArgumentException( - "VcnTransportInfo requires either non-null WifiInfo or valid subId"); - } - + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId, long redactions) { mWifiInfo = wifiInfo; mSubId = subId; + mRedactions = redactions; } /** @@ -86,8 +108,19 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return mSubId; } + /** + * Gets the redaction scheme + * + * @hide + */ + @VisibleForTesting(visibility = PRIVATE) + public long getRedaction() { + return mRedactions; + } + @Override public int hashCode() { + // mRedactions not hashed, as it is a transient, for control of parcelling return Objects.hash(mWifiInfo, mSubId); } @@ -96,6 +129,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; + // mRedactions not compared, as it is a transient, for control of parcelling return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; } @@ -105,17 +139,59 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return 0; } + @Override + @NonNull + public TransportInfo makeCopy(long redactions) { + return new VcnTransportInfo( + mWifiInfo == null ? null : mWifiInfo.makeCopy(redactions), mSubId, redactions); + } + + @Override + public long getApplicableRedactions() { + long redactions = REDACT_FOR_NETWORK_SETTINGS; + + // Add additional wifi redactions if necessary + if (mWifiInfo != null) { + redactions |= mWifiInfo.getApplicableRedactions(); + } + + return redactions; + } + + private boolean shouldParcelNetworkSettingsFields() { + return (mRedactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) == 0; + } + /** {@inheritDoc} */ @Override - public void writeToParcel(@NonNull Parcel dest, int flags) {} + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(shouldParcelNetworkSettingsFields() ? mSubId : INVALID_SUBSCRIPTION_ID); + dest.writeParcelable( + shouldParcelNetworkSettingsFields() ? (Parcelable) mWifiInfo : null, flags); + } + + @Override + public String toString() { + return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; + } /** Implement the Parcelable interface */ public static final @NonNull Creator CREATOR = new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { - // return null instead of a default VcnTransportInfo to avoid leaking - // information about this being a VCN Network (instead of macro cellular, etc) - return null; + final int subId = in.readInt(); + final WifiInfo wifiInfo = in.readParcelable(null); + + // If all fields are their null values, return null TransportInfo to avoid + // leaking information about this being a VCN Network (instead of macro + // cellular, etc) + if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { + return null; + } + + // Prevent further forwarding by redacting everything in future parcels from + // this VcnTransportInfo + return new VcnTransportInfo(wifiInfo, subId, REDACT_ALL); } public VcnTransportInfo[] newArray(int size) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 31561901be..582275d054 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -16,6 +16,8 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; @@ -36,6 +38,12 @@ public class VcnTransportInfoTest { private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); + @Test + public void testRedactionDefaults() { + assertEquals(REDACT_ALL, CELL_UNDERLYING_INFO.getRedaction()); + assertEquals(REDACT_ALL, WIFI_UNDERLYING_INFO.getRedaction()); + } + @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); @@ -50,6 +58,18 @@ public class VcnTransportInfoTest { assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId()); } + @Test + public void testMakeCopySetsRedactions() { + assertEquals( + REDACT_FOR_NETWORK_SETTINGS, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getRedaction()); + assertEquals( + REDACT_FOR_NETWORK_SETTINGS, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getRedaction()); + } + @Test public void testEquals() { assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO); @@ -64,8 +84,29 @@ public class VcnTransportInfoTest { } private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { + // Verify redacted by default Parcel parcel = Parcel.obtain(); vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); } + + @Test + public void testParcelUnparcelNotRedactedForSysUi() { + verifyParcelingForSysUi(CELL_UNDERLYING_INFO); + verifyParcelingForSysUi(WIFI_UNDERLYING_INFO); + } + + private void verifyParcelingForSysUi(VcnTransportInfo vcnTransportInfo) { + // Allow fully unredacted; SysUI will have all the relevant permissions. + final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(0); + final Parcel parcel = Parcel.obtain(); + unRedacted.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + + final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel); + assertEquals(vcnTransportInfo, unparceled); + assertEquals(REDACT_ALL, unparceled.getRedaction()); + } } From 24c93cc63862cb436d69b5f1495431e2819356a3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 28 Apr 2021 15:11:48 -0700 Subject: [PATCH 0203/1057] Update set|getRetryIntervalsMs to Millis Bug: 184612525 Test: atest CtsVcnTestCases Change-Id: Id00563bfaa2a72a4ef098ef49dc334079dc6a3a0 --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index a7d7a7886b..0e6f9fcb65 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -129,7 +129,7 @@ public class VcnManagerTest { new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, tunnelParams) .addExposedCapability(NET_CAPABILITY_INTERNET) .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) - .setRetryIntervalsMs( + .setRetryIntervalsMillis( new long[] { TimeUnit.SECONDS.toMillis(1), TimeUnit.MINUTES.toMillis(1), From 26d2771b52494a13d0b7f7b47deba3406260d46c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 30 Apr 2021 01:14:05 -0700 Subject: [PATCH 0204/1057] Trigger reevaluation of all requests when mobile data state changes This change ensures mobile data state changes result in the reevaluation of all NetworkRequests; ensuring that any requests that can be fulfilled as a result of the mobile data state change start the relevant GatewayConnections Test: atest FrameworksVcnTests Change-Id: I442ca2ee0fc8b9ad962a2491ddc3818535d9e042 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 12 ++++++++++++ .../unit/java/com/android/server/vcn/VcnTest.java | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index cccb0968fc..e1747f71d5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -396,6 +396,15 @@ public class Vcn extends Handler { continue; } + // This should never happen, by virtue of checking for the above check for + // pre-existing VcnGatewayConnections that satisfy a given request, but if state + // that affects the satsifying of requests changes, this is theoretically possible. + if (mVcnGatewayConnections.containsKey(gatewayConnectionConfig)) { + Slog.wtf(getLogTag(), "Attempted to bring up VcnGatewayConnection for config " + + "with existing VcnGatewayConnection"); + return; + } + final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( mVcnContext, @@ -467,6 +476,9 @@ public class Vcn extends Handler { } } } + + // Trigger re-evaluation of all requests; mobile data state impacts supported caps. + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 736fabdb1a..f681ee19ab 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -388,8 +388,9 @@ public class VcnTest { final ContentObserver contentObserver = captor.getValue(); // Start VcnGatewayConnections + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); - triggerVcnRequestListeners(verifyAndGetRequestListener()); + triggerVcnRequestListeners(requestListener); final Map gateways = mVcn.getVcnGatewayConnectionConfigMap(); @@ -411,6 +412,9 @@ public class VcnTest { } } + if (startingToggleState != endingToggleState) { + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } From ae003a090cde36fc50b51d9e66aa3f24d8a70b9e Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 3 May 2021 15:18:08 -0700 Subject: [PATCH 0205/1057] Notify policy listeners when VCN subIds change. This CL updates VcnManagementService to notify policy listeners when the subIds for any VCN instances change. This is necessary to ensure that NetworkFactories properly update their Networks in the event that a Network comes up under an existing VCN are properly marked as VCN-managed. Bug: 187112989 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Iecab1226119c8fd876131c381647267f18339db2 --- .../android/server/VcnManagementService.java | 20 +++++++++++++++ .../server/VcnManagementServiceTest.java | 25 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 45eb77453d..29c26e0158 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -87,6 +87,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -431,6 +432,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { // Startup VCN instances synchronized (mLock) { + final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; // Start any VCN instances as necessary @@ -478,10 +480,28 @@ public class VcnManagementService extends IVcnManagementService.Stub { entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); } } + + final Map> oldSubGrpMappings = + getSubGroupToSubIdMappings(oldSnapshot); + final Map> currSubGrpMappings = + getSubGroupToSubIdMappings(mLastSnapshot); + if (!currSubGrpMappings.equals(oldSubGrpMappings)) { + notifyAllPolicyListenersLocked(); + } } } } + @GuardedBy("mLock") + private Map> getSubGroupToSubIdMappings( + @NonNull TelephonySubscriptionSnapshot snapshot) { + final Map> subGrpMappings = new ArrayMap<>(); + for (ParcelUuid subGrp : mVcns.keySet()) { + subGrpMappings.put(subGrp, snapshot.getAllSubIdsInGroup(subGrp)); + } + return subGrpMappings; + } + @GuardedBy("mLock") private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index aa4b5f8e20..9ecd82ff6b 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -77,6 +77,7 @@ import android.os.test.TestLooper; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -98,6 +99,7 @@ import java.io.FileNotFoundException; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -326,6 +328,17 @@ public class VcnManagementServiceTest { return subIdToGroupMap.get(invocation.getArgument(0)); }).when(snapshot).getGroupForSubId(anyInt()); + doAnswer(invocation -> { + final ParcelUuid subGrp = invocation.getArgument(0); + final Set subIds = new ArraySet<>(); + for (Entry entry : subIdToGroupMap.entrySet()) { + if (entry.getValue().equals(subGrp)) { + subIds.add(entry.getKey()); + } + } + return subIds; + }).when(snapshot).getAllSubIdsInGroup(any()); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); cb.onNewSnapshot(snapshot); @@ -914,6 +927,18 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception { + startAndGetVcnInstance(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(TEST_UUID_2), + Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); + + verify(mMockPolicyListener).onPolicyChanged(); + } + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot, From 3472eb82e2e894cb0993d695eca4780cef5bef23 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 4 May 2021 16:54:45 -0700 Subject: [PATCH 0206/1057] Set NOT_VCN_MANAGED capability for Networks in VcnMgmtSvc. This CL updates VcnManagementService to set the NOT_VCN_MANAGED bit for Networks that are not VCN-managed. This ensures that Networks correctly regain the NOT_VCN_MANAGED bit after leaving a VCN. Bug: Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I01ffdde246e602296673675add58c47c92b15994 --- Vcn/service-b/src/com/android/server/VcnManagementService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 29c26e0158..471d2af278 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -835,6 +835,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (isVcnManagedNetwork) { ncBuilder.removeCapability( NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } else { + ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } if (isRestrictedCarrierWifi) { From c681382c4cdc5a97134d14c19bf33dba4114a8d9 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 28 Apr 2021 11:23:55 -0700 Subject: [PATCH 0207/1057] CTS test VcnGatewayConnectionConfig. This CL adds CTS coverage for all VcnGateayConnectionConfig APIs. Bug: 183240199 Bug: 183240103 Test: atest CtsVcnTestCases Change-Id: I4b4bd3bd7baf2e0c7e2f83968b8794097493b695 --- .../cts/VcnGatewayConnectionConfigTest.java | 79 +++++++++++++++++++ .../android/net/vcn/cts/VcnManagerTest.java | 65 +-------------- .../src/android/net/vcn/cts/VcnTestBase.java | 65 +++++++++++++++ 3 files changed, 147 insertions(+), 62 deletions(-) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java new file mode 100644 index 0000000000..23990d4911 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -0,0 +1,79 @@ +/* + * 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 android.net.vcn.cts; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.vcn.VcnGatewayConnectionConfig; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class VcnGatewayConnectionConfigTest extends VcnTestBase { + private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; + private static final long[] RETRY_INTERNAL_MILLIS = + new long[] { + TimeUnit.SECONDS.toMillis(1), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.HOURS.toMillis(1) + }; + private static final int MAX_MTU = 1360; + + private static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { + return new VcnGatewayConnectionConfig.Builder( + VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams()) + .addExposedCapability(NET_CAPABILITY_INTERNET) + .setRetryIntervalsMillis(RETRY_INTERNAL_MILLIS) + .setMaxMtu(MAX_MTU); + } + + public static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { + return buildVcnGatewayConnectionConfigBase().build(); + } + + @Test + public void testBuildVcnGatewayConnectionConfig() throws Exception { + final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfig(); + + assertEquals(VCN_GATEWAY_CONNECTION_NAME, gatewayConnConfig.getGatewayConnectionName()); + assertEquals(buildTunnelConnectionParams(), gatewayConnConfig.getTunnelConnectionParams()); + assertArrayEquals( + new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities()); + assertArrayEquals(RETRY_INTERNAL_MILLIS, gatewayConnConfig.getRetryIntervalsMillis()); + } + + @Test + public void testBuilderAddRemove() throws Exception { + final VcnGatewayConnectionConfig gatewayConnConfig = + buildVcnGatewayConnectionConfigBase() + .addExposedCapability(NET_CAPABILITY_DUN) + .removeExposedCapability(NET_CAPABILITY_DUN) + .build(); + + assertArrayEquals( + new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities()); + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 0e6f9fcb65..e406815c34 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -17,10 +17,6 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; @@ -34,15 +30,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; -import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeFqdnIdentification; -import android.net.ipsec.ike.IkeSaProposal; -import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.IkeTunnelConnectionParams; -import android.net.ipsec.ike.SaProposal; -import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.vcn.VcnConfig; -import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.os.ParcelUuid; import android.telephony.SubscriptionManager; @@ -63,15 +51,13 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) -public class VcnManagerTest { +public class VcnManagerTest extends VcnTestBase { private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; private static final Executor INLINE_EXECUTOR = Runnable::run; - private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; - private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; @@ -92,54 +78,9 @@ public class VcnManagerTest { } private VcnConfig buildVcnConfig() { - final IkeSaProposal ikeProposal = - new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) - .addDhGroup(DH_GROUP_2048_BIT_MODP) - .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) - .build(); - - final String serverHostname = "2001:db8:1::100"; - final String testLocalId = "test.client.com"; - final String testRemoteId = "test.server.com"; - final byte[] psk = "psk".getBytes(); - - final IkeSessionParams ikeParams = - new IkeSessionParams.Builder() - .setServerHostname(serverHostname) - .addSaProposal(ikeProposal) - .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) - .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) - .setAuthPsk(psk) - .build(); - - final ChildSaProposal childProposal = - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) - .build(); - final TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); - - final IkeTunnelConnectionParams tunnelParams = - new IkeTunnelConnectionParams(ikeParams, childParams); - - final VcnGatewayConnectionConfig gatewayConnConfig = - new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, tunnelParams) - .addExposedCapability(NET_CAPABILITY_INTERNET) - .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET) - .setRetryIntervalsMillis( - new long[] { - TimeUnit.SECONDS.toMillis(1), - TimeUnit.MINUTES.toMillis(1), - TimeUnit.HOURS.toMillis(1) - }) - .setMaxMtu(1360) - .build(); - return new VcnConfig.Builder(mContext) - .addGatewayConnectionConfig(gatewayConnConfig) + .addGatewayConnectionConfig( + VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig()) .build(); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java new file mode 100644 index 0000000000..54aa1e97b7 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -0,0 +1,65 @@ +/* + * 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 android.net.vcn.cts; + +import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.ipsec.ike.SaProposal; +import android.net.ipsec.ike.TunnelModeChildSessionParams; + +public class VcnTestBase { + protected static IkeTunnelConnectionParams buildTunnelConnectionParams() { + final IkeSaProposal ikeProposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addDhGroup(DH_GROUP_2048_BIT_MODP) + .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) + .build(); + + final String serverHostname = "2001:db8:1::100"; + final String testLocalId = "test.client.com"; + final String testRemoteId = "test.server.com"; + final byte[] psk = "psk".getBytes(); + + final IkeSessionParams ikeParams = + new IkeSessionParams.Builder() + .setServerHostname(serverHostname) + .addSaProposal(ikeProposal) + .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) + .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) + .setAuthPsk(psk) + .build(); + + final ChildSaProposal childProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .build(); + final TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); + + return new IkeTunnelConnectionParams(ikeParams, childParams); + } +} From 4fc5e657c8d58521702767a7faad07e216d8045a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 15 Apr 2021 11:59:16 -0700 Subject: [PATCH 0208/1057] Apply transform to FWD policy if configured to provide tethering This change allows the VCN to trigger the application of IpSecTransforms as in the FWD path, ensuring that tethering works across interfaces Bug: 185495453 Test: atest FrameworksVcnTests Test: manual testing with cross-device tethering Change-Id: I90fc77226ca971dbd8ac549b96a4828da1079cd5 --- .../server/vcn/VcnGatewayConnection.java | 13 ++++++ ...cnGatewayConnectionConnectedStateTest.java | 45 +++++++++++++++++-- .../vcn/VcnGatewayConnectionTestBase.java | 2 +- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 65b947c1fc..935a4744e8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1602,11 +1602,24 @@ public class VcnGatewayConnection extends StateMachine { @NonNull Network underlyingNetwork, @NonNull IpSecTransform transform, int direction) { + if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) { + Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction); + } + try { tunnelIface.setUnderlyingNetwork(underlyingNetwork); // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); + + // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as + // needed) + final Set exposedCaps = mConnectionConfig.getAllExposedCapabilities(); + if (direction == IpSecManager.DIRECTION_IN + && exposedCaps.contains(NET_CAPABILITY_DUN)) { + mIpSecManager.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_FWD, transform); + } } catch (IOException e) { Slog.d(TAG, "Transform application failed for network " + token, e); sessionLost(token, e); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index eedaac4829..39f7386cbb 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -16,8 +16,11 @@ package com.android.server.vcn; +import static android.net.IpSecManager.DIRECTION_FWD; import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; +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_WIFI; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; @@ -54,6 +57,8 @@ import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; import androidx.test.filters.SmallTest; @@ -143,8 +148,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } - @Test - public void testCreatedTransformsAreApplied() throws Exception { + private void verifyVcnTransformsApplied( + VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform) + throws Exception { for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction); mTestLooper.dispatchAll(); @@ -154,7 +160,40 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } - assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + verify(mIpSecSvc, expectForwardTransform ? times(1) : never()) + .applyTunnelModeTransform( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any()); + + assertEquals(vcnGatewayConnection.mConnectedState, vcnGatewayConnection.getCurrentState()); + } + + @Test + public void testCreatedTransformsAreApplied() throws Exception { + verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */); + } + + @Test + public void testCreatedTransformsAreAppliedWithDun() throws Exception { + VcnGatewayConnectionConfig gatewayConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps( + NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); + VcnGatewayConnection gatewayConnection = + new VcnGatewayConnection( + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + gatewayConfig, + mGatewayStatusCallback, + true /* isMobileDataEnabled */, + mDeps); + gatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); + final VcnIkeSession session = + gatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); + gatewayConnection.setIkeSession(session); + gatewayConnection.transitionTo(gatewayConnection.mConnectedState); + mTestLooper.dispatchAll(); + + verifyVcnTransformsApplied(gatewayConnection, true /* expectForwardTransform */); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 284f1f8865..1ecb4c9ee2 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -220,7 +220,7 @@ public class VcnGatewayConnectionTestBase { protected VcnChildSessionCallback getChildSessionCallback() { ArgumentCaptor captor = ArgumentCaptor.forClass(ChildSessionCallback.class); - verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture()); + verify(mDeps, atLeastOnce()).newIkeSession(any(), any(), any(), any(), captor.capture()); return (VcnChildSessionCallback) captor.getValue(); } From 2816231d89a1a8b6239495ffb78026da062817ee Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 30 Apr 2021 01:16:48 -0700 Subject: [PATCH 0209/1057] Add additional logging to improve debugability of VcnManagementService Test: atest FrameworksVcnTests Change-Id: I23af20ea655e11934f6ac679c1bfc0943d5a148f --- .../net/vcn/VcnNetworkPolicyResult.java | 10 +++ .../net/vcn/VcnUnderlyingNetworkPolicy.java | 5 ++ .../android/server/VcnManagementService.java | 17 ++-- .../src/com/android/server/vcn/Vcn.java | 36 ++++++--- .../server/vcn/VcnGatewayConnection.java | 80 ++++++++++++++++++- 5 files changed, 130 insertions(+), 18 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index 5e93820063..14e70cfeb1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -87,6 +87,16 @@ public final class VcnNetworkPolicyResult implements Parcelable { && mNetworkCapabilities.equals(that.mNetworkCapabilities); } + @Override + public String toString() { + return "VcnNetworkPolicyResult { " + + "mIsTeardownRequested = " + + mIsTearDownRequested + + ", mNetworkCapabilities" + + mNetworkCapabilities + + " }"; + } + /** {@inheritDoc} */ @Override public int describeContents() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index b47d564241..b0d4f3be24 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -85,6 +85,11 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult); } + @Override + public String toString() { + return mVcnNetworkPolicyResult.toString(); + } + /** {@inheritDoc} */ @Override public int describeContents() { diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 471d2af278..1fd637ad20 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -434,6 +434,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; + Slog.d(TAG, "new snapshot: " + mLastSnapshot); // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { @@ -536,7 +537,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. @@ -558,7 +559,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startOrUpdateVcnLocked( @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); + Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); @@ -584,7 +585,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!config.getProvisioningPackageName().equals(opPkgName)) { throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); } - Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup); + Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); @@ -609,7 +610,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(opPkgName, "opPkgName was null"); - Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); + Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); @@ -845,8 +846,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { } final NetworkCapabilities result = ncBuilder.build(); - return new VcnUnderlyingNetworkPolicy( + final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result); + + if (VDBG) { + Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + + "; and lp: " + linkProperties + "; result = " + policy); + } + return policy; }); } diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index e1747f71d5..edb042fd34 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -311,7 +311,9 @@ public class Vcn extends Handler { private void handleConfigUpdated(@NonNull VcnConfig config) { // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode() - Slog.v(getLogTag(), "Config updated: config = " + config.hashCode()); + Slog.d( + getLogTag(), + "Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode()); mConfig = config; @@ -340,6 +342,7 @@ public class Vcn extends Handler { } private void handleTeardown() { + Slog.d(getLogTag(), "Tearing down"); mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener); for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { @@ -350,6 +353,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { + Slog.d(getLogTag(), "VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -365,21 +369,24 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); + Slog.d( + getLogTag(), + "Safe mode " + + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } } private void handleNetworkRequested(@NonNull NetworkRequest request) { - Slog.v(getLogTag(), "Received request " + request); + if (VDBG) { + Slog.v(getLogTag(), "Received request " + request); + } // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - if (VDBG) { - Slog.v( - getLogTag(), - "Request already satisfied by existing VcnGatewayConnection: " - + request); - } + Slog.d( + getLogTag(), + "Request already satisfied by existing VcnGatewayConnection: " + request); return; } } @@ -389,7 +396,7 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); + Slog.d(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { // Skip; this network does not provide any services if mobile data is disabled. @@ -414,8 +421,14 @@ public class Vcn extends Handler { new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig), mIsMobileDataEnabled); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); + + return; } } + + if (VDBG) { + Slog.v(getLogTag(), "Request could not be fulfilled by VCN: " + request); + } } private Set getExposedCapabilitiesForMobileDataState( @@ -432,7 +445,7 @@ public class Vcn extends Handler { } private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { - Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); + Slog.d(getLogTag(), "VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied @@ -479,6 +492,8 @@ public class Vcn extends Handler { // Trigger re-evaluation of all requests; mobile data state impacts supported caps. mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + + Slog.d(getLogTag(), "Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); } } @@ -521,6 +536,7 @@ public class Vcn extends Handler { pw.increaseIndent(); pw.println("mCurrentStatus: " + mCurrentStatus); + pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled); pw.println("mVcnGatewayConnections:"); for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 65b947c1fc..46fd22810a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -701,6 +701,7 @@ public class VcnGatewayConnection extends StateMachine { *

      Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { + Slog.d(TAG, "Triggering async teardown"); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); @@ -710,6 +711,8 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void onQuitting() { + Slog.d(TAG, "Quitting VcnGatewayConnection"); + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); @@ -750,6 +753,11 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); + Slog.d( + TAG, + "Selected underlying network changed: " + + (underlying == null ? null : underlying.network)); + // TODO(b/179091925): Move the delayed-message handling to BaseState // If underlying is null, all underlying networks have been lost. Disconnect VCN after a @@ -774,6 +782,10 @@ public class VcnGatewayConnection extends StateMachine { if (!mIsQuitting) { mWakeLock.acquire(); + + if (VDBG) { + Slog.v(TAG, "Wakelock acquired: " + mWakeLock); + } } } @@ -781,6 +793,10 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.ensureRunningOnLooperThread(); mWakeLock.release(); + + if (VDBG) { + Slog.v(TAG, "Wakelock released: " + mWakeLock); + } } /** @@ -935,10 +951,17 @@ public class VcnGatewayConnection extends StateMachine { } private void setTeardownTimeoutAlarm() { + if (VDBG) { + Slog.v(TAG, "Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken); + } + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mTeardownTimeoutAlarm != null) { - Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set"); + Slog.wtf( + TAG, + "mTeardownTimeoutAlarm should be null before being set; mCurrentToken: " + + mCurrentToken); } final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken); @@ -950,6 +973,10 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelTeardownTimeoutAlarm() { + if (VDBG) { + Slog.v(TAG, "Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken); + } + if (mTeardownTimeoutAlarm != null) { mTeardownTimeoutAlarm.cancel(); mTeardownTimeoutAlarm = null; @@ -960,6 +987,13 @@ public class VcnGatewayConnection extends StateMachine { } private void setDisconnectRequestAlarm() { + if (VDBG) { + Slog.v( + TAG, + "Setting alarm to disconnect due to underlying network loss; mCurrentToken: " + + mCurrentToken); + } + // Only schedule a NEW alarm if none is already set. if (mDisconnectRequestAlarm != null) { return; @@ -980,6 +1014,13 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelDisconnectRequestAlarm() { + if (VDBG) { + Slog.v( + TAG, + "Cancelling alarm to disconnect due to underlying network loss; mCurrentToken: " + + mCurrentToken); + } + if (mDisconnectRequestAlarm != null) { mDisconnectRequestAlarm.cancel(); mDisconnectRequestAlarm = null; @@ -993,10 +1034,17 @@ public class VcnGatewayConnection extends StateMachine { } private void setRetryTimeoutAlarm(long delay) { + if (VDBG) { + Slog.v(TAG, "Setting retry alarm; mCurrentToken: " + mCurrentToken); + } + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mRetryTimeoutAlarm != null) { - Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set"); + Slog.wtf( + TAG, + "mRetryTimeoutAlarm should be null before being set; mCurrentToken: " + + mCurrentToken); } final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken); @@ -1004,6 +1052,10 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelRetryTimeoutAlarm() { + if (VDBG) { + Slog.v(TAG, "Cancel retry alarm; mCurrentToken: " + mCurrentToken); + } + if (mRetryTimeoutAlarm != null) { mRetryTimeoutAlarm.cancel(); mRetryTimeoutAlarm = null; @@ -1014,6 +1066,10 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { + if (VDBG) { + Slog.v(TAG, "Setting safe mode alarm; mCurrentToken: " + mCurrentToken); + } + // Only schedule a NEW alarm if none is already set. if (mSafeModeTimeoutAlarm != null) { return; @@ -1028,6 +1084,10 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelSafeModeAlarm() { + if (VDBG) { + Slog.v(TAG, "Cancel safe mode alarm; mCurrentToken: " + mCurrentToken); + } + if (mSafeModeTimeoutAlarm != null) { mSafeModeTimeoutAlarm.cancel(); mSafeModeTimeoutAlarm = null; @@ -1092,6 +1152,15 @@ public class VcnGatewayConnection extends StateMachine { + exception.getMessage(); } + Slog.d( + TAG, + "Encountered error; code=" + + errorCode + + ", exceptionClass=" + + exceptionClass + + ", exceptionMessage=" + + exceptionMessage); + mGatewayStatusCallback.onGatewayConnectionError( mConnectionConfig.getGatewayConnectionName(), errorCode, @@ -1234,7 +1303,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.v(TAG, "Tearing down. Cause: " + info.reason); + Slog.d(TAG, "Tearing down. Cause: " + info.reason); mIsQuitting = info.shouldQuit; teardownNetwork(); @@ -1250,6 +1319,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleSafeModeTimeoutExceeded() { mSafeModeTimeoutAlarm = null; + Slog.d(TAG, "Entering safe mode after timeout exceeded"); // Connectivity for this GatewayConnection is broken; tear down the Network. teardownNetwork(); @@ -1722,6 +1792,8 @@ public class VcnGatewayConnection extends StateMachine { } private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) { + Slog.v(TAG, "Migration completed: " + mUnderlying.network); + applyTransform( mCurrentToken, mTunnelIface, @@ -1744,6 +1816,8 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; if (mUnderlying == null) { + Slog.v(TAG, "Underlying network lost"); + // Ignored for now; a new network may be coming up. If none does, the delayed // NETWORK_LOST disconnect will be fired, and tear down the session + network. return; From f8e76570802c7293b6c32825532c9ed6d66f9931 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 7 May 2021 16:00:15 -0700 Subject: [PATCH 0210/1057] Add log prefixes to uniquely identify each VCN/gwConn This change adds additional logging prefixes to uniquely identify connections and vcn instances to allow for better debugging. Test: atest FrameworksVcnTests Change-Id: Ied1aa2b2502c9cbe59358755eb65ed369fdbd987 --- .../src/android/net/vcn/util/LogUtils.java | 39 ++++ .../src/com/android/server/vcn/Vcn.java | 78 ++++--- .../server/vcn/VcnGatewayConnection.java | 194 +++++++++--------- 3 files changed, 190 insertions(+), 121 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/util/LogUtils.java diff --git a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java new file mode 100644 index 0000000000..93728ceb27 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java @@ -0,0 +1,39 @@ +/* + * 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.server.vcn.util; + +import android.annotation.Nullable; +import android.os.ParcelUuid; + +import com.android.internal.util.HexDump; + +/** @hide */ +public class LogUtils { + /** + * Returns the hash of the subscription group in hexadecimal format. + * + * @return the hexadecimal encoded string if uuid was non-null, else {@code null} + */ + @Nullable + public static String getHashedSubscriptionGroup(@Nullable ParcelUuid uuid) { + if (uuid == null) { + return null; + } + + return HexDump.toHexString(uuid.hashCode()); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index edb042fd34..f918827e96 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.util.LogUtils; import java.util.Arrays; import java.util.Collections; @@ -305,15 +306,13 @@ public class Vcn extends Handler { handleTeardown(); break; default: - Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); + logWtf("Unknown msg.what: " + msg.what); } } private void handleConfigUpdated(@NonNull VcnConfig config) { // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode() - Slog.d( - getLogTag(), - "Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode()); + logDbg("Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode()); mConfig = config; @@ -328,8 +327,7 @@ public class Vcn extends Handler { // connection details may have changed). if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { if (gatewayConnection == null) { - Slog.wtf( - getLogTag(), "Found gatewayConnectionConfig without GatewayConnection"); + logWtf("Found gatewayConnectionConfig without GatewayConnection"); } else { gatewayConnection.teardownAsynchronously(); } @@ -342,7 +340,7 @@ public class Vcn extends Handler { } private void handleTeardown() { - Slog.d(getLogTag(), "Tearing down"); + logDbg("Tearing down"); mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener); for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { @@ -353,7 +351,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { - Slog.d(getLogTag(), "VcnGatewayConnection safe mode status changed"); + logDbg("VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -369,24 +367,19 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); - Slog.d( - getLogTag(), + logDbg( "Safe mode " + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } } private void handleNetworkRequested(@NonNull NetworkRequest request) { - if (VDBG) { - Slog.v(getLogTag(), "Received request " + request); - } + logVdbg("Received request " + request); // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.d( - getLogTag(), - "Request already satisfied by existing VcnGatewayConnection: " + request); + logDbg("Request already satisfied by existing VcnGatewayConnection: " + request); return; } } @@ -396,7 +389,7 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.d(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); + logDbg("Bringing up new VcnGatewayConnection for request " + request); if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { // Skip; this network does not provide any services if mobile data is disabled. @@ -407,8 +400,9 @@ public class Vcn extends Handler { // pre-existing VcnGatewayConnections that satisfy a given request, but if state // that affects the satsifying of requests changes, this is theoretically possible. if (mVcnGatewayConnections.containsKey(gatewayConnectionConfig)) { - Slog.wtf(getLogTag(), "Attempted to bring up VcnGatewayConnection for config " - + "with existing VcnGatewayConnection"); + logWtf( + "Attempted to bring up VcnGatewayConnection for config " + + "with existing VcnGatewayConnection"); return; } @@ -426,9 +420,7 @@ public class Vcn extends Handler { } } - if (VDBG) { - Slog.v(getLogTag(), "Request could not be fulfilled by VCN: " + request); - } + logVdbg("Request could not be fulfilled by VCN: " + request); } private Set getExposedCapabilitiesForMobileDataState( @@ -445,7 +437,7 @@ public class Vcn extends Handler { } private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { - Slog.d(getLogTag(), "VcnGatewayConnection quit: " + config); + logDbg("VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied @@ -480,9 +472,7 @@ public class Vcn extends Handler { if (exposedCaps.contains(NET_CAPABILITY_INTERNET) || exposedCaps.contains(NET_CAPABILITY_DUN)) { if (gatewayConnection == null) { - Slog.wtf( - getLogTag(), - "Found gatewayConnectionConfig without GatewayConnection"); + logWtf("Found gatewayConnectionConfig without" + " GatewayConnection"); } else { // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown. gatewayConnection.teardownAsynchronously(); @@ -493,7 +483,7 @@ public class Vcn extends Handler { // Trigger re-evaluation of all requests; mobile data state impacts supported caps. mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); - Slog.d(getLogTag(), "Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); + logDbg("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); } } @@ -522,8 +512,38 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } - private String getLogTag() { - return TAG + " [" + mSubscriptionGroup.hashCode() + "]"; + private String getLogPrefix() { + return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: "; + } + + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, getLogPrefix() + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, getLogPrefix() + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, getLogPrefix() + msg, tr); + } + + private void logErr(String msg) { + Slog.e(TAG, getLogPrefix() + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, getLogPrefix() + msg, tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, getLogPrefix() + msg, tr); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 46fd22810a..cb435fdcf7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -88,6 +88,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; import java.io.IOException; @@ -701,7 +702,7 @@ public class VcnGatewayConnection extends StateMachine { *

      Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - Slog.d(TAG, "Triggering async teardown"); + logDbg("Triggering async teardown"); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); @@ -711,7 +712,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void onQuitting() { - Slog.d(TAG, "Quitting VcnGatewayConnection"); + logDbg("Quitting VcnGatewayConnection"); // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { @@ -753,8 +754,7 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); - Slog.d( - TAG, + logDbg( "Selected underlying network changed: " + (underlying == null ? null : underlying.network)); @@ -783,9 +783,7 @@ public class VcnGatewayConnection extends StateMachine { if (!mIsQuitting) { mWakeLock.acquire(); - if (VDBG) { - Slog.v(TAG, "Wakelock acquired: " + mWakeLock); - } + logVdbg("Wakelock acquired: " + mWakeLock); } } @@ -794,9 +792,7 @@ public class VcnGatewayConnection extends StateMachine { mWakeLock.release(); - if (VDBG) { - Slog.v(TAG, "Wakelock released: " + mWakeLock); - } + logVdbg("Wakelock released: " + mWakeLock); } /** @@ -814,8 +810,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what); @@ -823,8 +818,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, Object obj) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, obj); @@ -832,8 +826,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1); @@ -841,8 +834,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1, int arg2) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1, arg2); @@ -850,8 +842,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1, int arg2, Object obj) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1, arg2, obj); @@ -859,8 +850,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(Message msg) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(msg); @@ -951,15 +941,12 @@ public class VcnGatewayConnection extends StateMachine { } private void setTeardownTimeoutAlarm() { - if (VDBG) { - Slog.v(TAG, "Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken); // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mTeardownTimeoutAlarm != null) { - Slog.wtf( - TAG, + logWtf( "mTeardownTimeoutAlarm should be null before being set; mCurrentToken: " + mCurrentToken); } @@ -973,9 +960,7 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelTeardownTimeoutAlarm() { - if (VDBG) { - Slog.v(TAG, "Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken); if (mTeardownTimeoutAlarm != null) { mTeardownTimeoutAlarm.cancel(); @@ -987,12 +972,10 @@ public class VcnGatewayConnection extends StateMachine { } private void setDisconnectRequestAlarm() { - if (VDBG) { - Slog.v( - TAG, - "Setting alarm to disconnect due to underlying network loss; mCurrentToken: " - + mCurrentToken); - } + logVdbg( + "Setting alarm to disconnect due to underlying network loss;" + + " mCurrentToken: " + + mCurrentToken); // Only schedule a NEW alarm if none is already set. if (mDisconnectRequestAlarm != null) { @@ -1014,12 +997,10 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelDisconnectRequestAlarm() { - if (VDBG) { - Slog.v( - TAG, - "Cancelling alarm to disconnect due to underlying network loss; mCurrentToken: " - + mCurrentToken); - } + logVdbg( + "Cancelling alarm to disconnect due to underlying network loss;" + + " mCurrentToken: " + + mCurrentToken); if (mDisconnectRequestAlarm != null) { mDisconnectRequestAlarm.cancel(); @@ -1034,15 +1015,12 @@ public class VcnGatewayConnection extends StateMachine { } private void setRetryTimeoutAlarm(long delay) { - if (VDBG) { - Slog.v(TAG, "Setting retry alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Setting retry alarm; mCurrentToken: " + mCurrentToken); // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mRetryTimeoutAlarm != null) { - Slog.wtf( - TAG, + logWtf( "mRetryTimeoutAlarm should be null before being set; mCurrentToken: " + mCurrentToken); } @@ -1052,9 +1030,7 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelRetryTimeoutAlarm() { - if (VDBG) { - Slog.v(TAG, "Cancel retry alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Cancel retry alarm; mCurrentToken: " + mCurrentToken); if (mRetryTimeoutAlarm != null) { mRetryTimeoutAlarm.cancel(); @@ -1066,9 +1042,7 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { - if (VDBG) { - Slog.v(TAG, "Setting safe mode alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken); // Only schedule a NEW alarm if none is already set. if (mSafeModeTimeoutAlarm != null) { @@ -1084,9 +1058,7 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelSafeModeAlarm() { - if (VDBG) { - Slog.v(TAG, "Cancel safe mode alarm; mCurrentToken: " + mCurrentToken); - } + logVdbg("Cancel safe mode alarm; mCurrentToken: " + mCurrentToken); if (mSafeModeTimeoutAlarm != null) { mSafeModeTimeoutAlarm.cancel(); @@ -1152,8 +1124,7 @@ public class VcnGatewayConnection extends StateMachine { + exception.getMessage(); } - Slog.d( - TAG, + logDbg( "Encountered error; code=" + errorCode + ", exceptionClass=" @@ -1206,7 +1177,7 @@ public class VcnGatewayConnection extends StateMachine { try { enterState(); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1238,14 +1209,14 @@ public class VcnGatewayConnection extends StateMachine { public final boolean processMessage(Message msg) { final int token = msg.arg1; if (!isValidToken(token)) { - Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); + logDbg("Message called with obsolete token: " + token + "; what: " + msg.what); return HANDLED; } try { processStateMsg(msg); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1263,7 +1234,7 @@ public class VcnGatewayConnection extends StateMachine { try { exitState(); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1303,7 +1274,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.d(TAG, "Tearing down. Cause: " + info.reason); + logDbg("Tearing down. Cause: " + info.reason); mIsQuitting = info.shouldQuit; teardownNetwork(); @@ -1319,7 +1290,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleSafeModeTimeoutExceeded() { mSafeModeTimeoutAlarm = null; - Slog.d(TAG, "Entering safe mode after timeout exceeded"); + logDbg("Entering safe mode after timeout exceeded"); // Connectivity for this GatewayConnection is broken; tear down the Network. teardownNetwork(); @@ -1328,13 +1299,15 @@ public class VcnGatewayConnection extends StateMachine { } protected void logUnexpectedEvent(int what) { - Slog.d(TAG, String.format( - "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); + logDbg( + "Unexpected event code " + + what + + " in state " + + this.getClass().getSimpleName()); } protected void logWtfUnknownEvent(int what) { - Slog.wtf(TAG, String.format( - "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); + logWtf("Unknown event code " + what + " in state " + this.getClass().getSimpleName()); } } @@ -1351,7 +1324,7 @@ public class VcnGatewayConnection extends StateMachine { } if (mIkeSession != null || mNetworkAgent != null) { - Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); + logWtf("Active IKE Session or NetworkAgent in DisconnectedState"); } cancelSafeModeAlarm(); @@ -1419,7 +1392,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void enterState() throws Exception { if (mIkeSession == null) { - Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state."); + logWtf("IKE session was already closed when entering Disconnecting state."); sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken); return; } @@ -1506,7 +1479,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void enterState() { if (mIkeSession != null) { - Slog.wtf(TAG, "ConnectingState entered with active session"); + logWtf("ConnectingState entered with active session"); // Attempt to recover. mIkeSession.kill(); @@ -1525,7 +1498,7 @@ public class VcnGatewayConnection extends StateMachine { if (oldUnderlying == null) { // This should never happen, but if it does, there's likely a nasty bug. - Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?"); + logWtf("Old underlying network was null in connected state. Bug?"); } // If new underlying is null, all underlying networks have been lost; disconnect @@ -1620,11 +1593,11 @@ public class VcnGatewayConnection extends StateMachine { // new NetworkAgent replaces an old one before the unwanted() call // is processed. if (mNetworkAgent != agentRef) { - Slog.d(TAG, "unwanted() called on stale NetworkAgent"); + logDbg("unwanted() called on stale NetworkAgent"); return; } - Slog.d(TAG, "NetworkAgent was unwanted"); + logDbg("NetworkAgent was unwanted"); teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { @@ -1638,8 +1611,7 @@ public class VcnGatewayConnection extends StateMachine { setSafeModeAlarm(); break; default: - Slog.wtf( - TAG, + logWtf( "Unknown validation status " + status + "; ignoring"); @@ -1678,7 +1650,7 @@ public class VcnGatewayConnection extends StateMachine { // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); } catch (IOException e) { - Slog.d(TAG, "Transform application failed for network " + token, e); + logDbg("Transform application failed for network " + token, e); sessionLost(token, e); } } @@ -1712,7 +1684,7 @@ public class VcnGatewayConnection extends StateMachine { tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength()); } } catch (IOException e) { - Slog.d(TAG, "Adding address to tunnel failed for token " + token, e); + logDbg("Adding address to tunnel failed for token " + token, e); sessionLost(token, e); } } @@ -1792,7 +1764,7 @@ public class VcnGatewayConnection extends StateMachine { } private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) { - Slog.v(TAG, "Migration completed: " + mUnderlying.network); + logDbg("Migration completed: " + mUnderlying.network); applyTransform( mCurrentToken, @@ -1816,7 +1788,7 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; if (mUnderlying == null) { - Slog.v(TAG, "Underlying network lost"); + logDbg("Underlying network lost"); // Ignored for now; a new network may be coming up. If none does, the delayed // NETWORK_LOST disconnect will be fired, and tear down the session + network. @@ -1826,7 +1798,7 @@ public class VcnGatewayConnection extends StateMachine { // mUnderlying assumed non-null, given check above. // If network changed, migrate. Otherwise, update any existing networkAgent. if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) { - Slog.v(TAG, "Migrating to new network: " + mUnderlying.network); + logDbg("Migrating to new network: " + mUnderlying.network); mIkeSession.setNetwork(mUnderlying.network); } else { // oldUnderlying is non-null & underlying network itself has not changed @@ -1877,7 +1849,7 @@ public class VcnGatewayConnection extends StateMachine { mFailedAttempts++; if (mUnderlying == null) { - Slog.wtf(TAG, "Underlying network was null in retry state"); + logWtf("Underlying network was null in retry state"); transitionTo(mDisconnectedState); } else { // Safe to blindly set up, as it is cancelled and cleared on exiting this state @@ -2047,25 +2019,25 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { - Slog.v(TAG, "IkeOpened for token " + mToken); + logDbg("IkeOpened for token " + mToken); // Nothing to do here. } @Override public void onClosed() { - Slog.v(TAG, "IkeClosed for token " + mToken); + logDbg("IkeClosed for token " + mToken); sessionClosed(mToken, null); } @Override public void onClosedExceptionally(@NonNull IkeException exception) { - Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception); + logDbg("IkeClosedExceptionally for token " + mToken, exception); sessionClosed(mToken, exception); } @Override public void onError(@NonNull IkeProtocolException exception) { - Slog.v(TAG, "IkeError for token " + mToken, exception); + logDbg("IkeError for token " + mToken, exception); // Non-fatal, log and continue. } } @@ -2082,7 +2054,7 @@ public class VcnGatewayConnection extends StateMachine { /** Internal proxy method for injecting of mocked ChildSessionConfiguration */ @VisibleForTesting(visibility = Visibility.PRIVATE) void onOpened(@NonNull VcnChildSessionConfiguration childConfig) { - Slog.v(TAG, "ChildOpened for token " + mToken); + logDbg("ChildOpened for token " + mToken); childOpened(mToken, childConfig); } @@ -2093,19 +2065,19 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onClosed() { - Slog.v(TAG, "ChildClosed for token " + mToken); + logDbg("ChildClosed for token " + mToken); sessionLost(mToken, null); } @Override public void onClosedExceptionally(@NonNull IkeException exception) { - Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception); + logDbg("ChildClosedExceptionally for token " + mToken, exception); sessionLost(mToken, exception); } @Override public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) { - Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken); + logDbg("ChildTransformCreated; Direction: " + direction + "; token " + mToken); childTransformCreated(mToken, transform, direction); } @@ -2113,7 +2085,7 @@ public class VcnGatewayConnection extends StateMachine { public void onIpSecTransformsMigrated( @NonNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform outIpSecTransform) { - Slog.v(TAG, "ChildTransformsMigrated; token " + mToken); + logDbg("ChildTransformsMigrated; token " + mToken); migrationCompleted(mToken, inIpSecTransform, outIpSecTransform); } @@ -2121,10 +2093,48 @@ public class VcnGatewayConnection extends StateMachine { public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) { // Nothing to be done; no references to the IpSecTransform are held, and this transform // will be closed by the IKE library. - Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); + logDbg("ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); } } + private String getLogPrefix() { + return "[" + + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + + "-" + + mConnectionConfig.getGatewayConnectionName() + + "]: "; + } + + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, getLogPrefix() + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, getLogPrefix() + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, getLogPrefix() + msg, tr); + } + + private void logErr(String msg) { + Slog.e(TAG, getLogPrefix() + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, getLogPrefix() + msg, tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, getLogPrefix() + msg, tr); + } + /** * Dumps the state of this VcnGatewayConnection for logging and debugging purposes. * From 93af28bc4e8b45bf4a4dd97ecf81dbf9f46e6c62 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 10 May 2021 10:19:11 +0900 Subject: [PATCH 0211/1057] Immediately redact VcnTransportInfo. Redaction of NetworkCapabilities is changing from redacting at parcel time to redacting immediately when makeCopy() is called. Update VcnTransportInfo redaction accordingly. Bug: 183938194 Test: atest VcnTransportInfoTest Change-Id: I0c9406f426b66fd36b47d11799955def531c16ba --- .../src/android/net/vcn/VcnTransportInfo.java | 76 +++---------------- .../android/net/vcn/VcnTransportInfoTest.java | 57 ++++++-------- 2 files changed, 35 insertions(+), 98 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 0e9ccf144c..1f1818420b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -16,23 +16,17 @@ package android.net.vcn; -import static android.net.NetworkCapabilities.REDACT_ALL; -import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionManager; -import com.android.internal.annotations.VisibleForTesting; - import java.util.Objects; /** @@ -55,32 +49,17 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; - /** - * The redaction scheme to use when parcelling. - * - *

      The TransportInfo/NetworkCapabilities redaction mechanisms rely on redaction being - * performed at parcelling time. This means that the redaction scheme must be stored for later - * use. - * - *

      Since the redaction scheme itself is not parcelled, this field is listed as a transient. - * - *

      Defaults to REDACT_ALL when constructed using public constructors, or creating from - * parcels. - */ - private final transient long mRedactions; - public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, INVALID_SUBSCRIPTION_ID, REDACT_ALL); + this(wifiInfo, INVALID_SUBSCRIPTION_ID); } public VcnTransportInfo(int subId) { - this(null /* wifiInfo */, subId, REDACT_ALL); + this(null /* wifiInfo */, subId); } - private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId, long redactions) { + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { mWifiInfo = wifiInfo; mSubId = subId; - mRedactions = redactions; } /** @@ -102,25 +81,14 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. * * @return the Subscription ID if a cellular underlying Network is present, else {@link - * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}. + * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. */ public int getSubId() { return mSubId; } - /** - * Gets the redaction scheme - * - * @hide - */ - @VisibleForTesting(visibility = PRIVATE) - public long getRedaction() { - return mRedactions; - } - @Override public int hashCode() { - // mRedactions not hashed, as it is a transient, for control of parcelling return Objects.hash(mWifiInfo, mSubId); } @@ -128,8 +96,6 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public boolean equals(Object o) { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; - - // mRedactions not compared, as it is a transient, for control of parcelling return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; } @@ -143,31 +109,19 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @NonNull public TransportInfo makeCopy(long redactions) { return new VcnTransportInfo( - mWifiInfo == null ? null : mWifiInfo.makeCopy(redactions), mSubId, redactions); + (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId); } @Override public long getApplicableRedactions() { - long redactions = REDACT_FOR_NETWORK_SETTINGS; - - // Add additional wifi redactions if necessary - if (mWifiInfo != null) { - redactions |= mWifiInfo.getApplicableRedactions(); - } - - return redactions; - } - - private boolean shouldParcelNetworkSettingsFields() { - return (mRedactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) == 0; + return (mWifiInfo == null) ? REDACT_NONE : mWifiInfo.getApplicableRedactions(); } /** {@inheritDoc} */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(shouldParcelNetworkSettingsFields() ? mSubId : INVALID_SUBSCRIPTION_ID); - dest.writeParcelable( - shouldParcelNetworkSettingsFields() ? (Parcelable) mWifiInfo : null, flags); + dest.writeInt(mSubId); + dest.writeParcelable(mWifiInfo, flags); } @Override @@ -181,17 +135,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); final WifiInfo wifiInfo = in.readParcelable(null); - - // If all fields are their null values, return null TransportInfo to avoid - // leaking information about this being a VCN Network (instead of macro - // cellular, etc) - if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { - return null; - } - - // Prevent further forwarding by redacting everything in future parcels from - // this VcnTransportInfo - return new VcnTransportInfo(wifiInfo, subId, REDACT_ALL); + return new VcnTransportInfo(wifiInfo, subId); } public VcnTransportInfo[] newArray(int size) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 582275d054..00a0bffa15 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -16,14 +16,17 @@ package android.net.vcn; -import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.Parcel; @@ -38,12 +41,6 @@ public class VcnTransportInfoTest { private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); - @Test - public void testRedactionDefaults() { - assertEquals(REDACT_ALL, CELL_UNDERLYING_INFO.getRedaction()); - assertEquals(REDACT_ALL, WIFI_UNDERLYING_INFO.getRedaction()); - } - @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); @@ -59,15 +56,15 @@ public class VcnTransportInfoTest { } @Test - public void testMakeCopySetsRedactions() { + public void testMakeCopyRedactForAccessFineLocation() { assertEquals( - REDACT_FOR_NETWORK_SETTINGS, - ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) - .getRedaction()); + SUB_ID, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getSubId()); assertEquals( - REDACT_FOR_NETWORK_SETTINGS, - ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) - .getRedaction()); + WifiConfiguration.INVALID_NETWORK_ID, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getWifiInfo().getNetworkId()); } @Test @@ -78,35 +75,31 @@ public class VcnTransportInfoTest { } @Test - public void testParcelUnparcel() { - verifyParcelingIsNull(CELL_UNDERLYING_INFO); - verifyParcelingIsNull(WIFI_UNDERLYING_INFO); - } - - private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { - // Verify redacted by default - Parcel parcel = Parcel.obtain(); - vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); - parcel.setDataPosition(0); - - assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); + public void testApplicableRedactions() { + assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions()); + assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS + | REDACT_FOR_NETWORK_SETTINGS, + WIFI_UNDERLYING_INFO.getApplicableRedactions()); } @Test - public void testParcelUnparcelNotRedactedForSysUi() { - verifyParcelingForSysUi(CELL_UNDERLYING_INFO); - verifyParcelingForSysUi(WIFI_UNDERLYING_INFO); + public void testParcelNotRedactedForSysUi() { + VcnTransportInfo cellRedacted = parcelForSysUi(CELL_UNDERLYING_INFO); + assertEquals(SUB_ID, cellRedacted.getSubId()); + VcnTransportInfo wifiRedacted = parcelForSysUi(WIFI_UNDERLYING_INFO); + assertEquals(NETWORK_ID, wifiRedacted.getWifiInfo().getNetworkId()); } - private void verifyParcelingForSysUi(VcnTransportInfo vcnTransportInfo) { + private VcnTransportInfo parcelForSysUi(VcnTransportInfo vcnTransportInfo) { // Allow fully unredacted; SysUI will have all the relevant permissions. - final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(0); + final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy( + REDACT_NONE); final Parcel parcel = Parcel.obtain(); unRedacted.writeToParcel(parcel, 0 /* flags */); parcel.setDataPosition(0); final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel); assertEquals(vcnTransportInfo, unparceled); - assertEquals(REDACT_ALL, unparceled.getRedaction()); + return unparceled; } } From 45e33a117f329033c07112b0048ffefcab5594b5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 11 May 2021 15:06:56 -0700 Subject: [PATCH 0212/1057] Test VcnGatewayConnectionConfigs require MOBIKE. This CL adds CTS testing to verify that VcnGatewayConnectionConfigs require their IkeSessionParams to have MOBIKE configured. Bug: 187851560 Test: atest CtsVcnTestCases Change-Id: I5417a58561749c0389d39fece463e463498b52a9 --- .../cts/VcnGatewayConnectionConfigTest.java | 17 +++++++ .../src/android/net/vcn/cts/VcnTestBase.java | 44 +++++++++++-------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 23990d4911..20bdc0accd 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -18,10 +18,14 @@ package android.net.vcn.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.VcnGatewayConnectionConfig; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -76,4 +80,17 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { assertArrayEquals( new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities()); } + + @Test + public void testBuildWithoutMobikeEnabled() { + final IkeSessionParams ikeParams = + getIkeSessionParamsBase().removeIkeOption(IKE_OPTION_MOBIKE).build(); + final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(ikeParams); + + try { + new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, tunnelParams); + fail("Expected exception if MOBIKE not configured"); + } catch (IllegalArgumentException e) { + } + } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index 54aa1e97b7..7ed201eb0a 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -16,6 +16,7 @@ package android.net.vcn.cts; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; @@ -30,6 +31,24 @@ import android.net.ipsec.ike.TunnelModeChildSessionParams; public class VcnTestBase { protected static IkeTunnelConnectionParams buildTunnelConnectionParams() { + final IkeSessionParams ikeParams = getIkeSessionParamsBase().build(); + return buildTunnelConnectionParams(ikeParams); + } + + protected static IkeTunnelConnectionParams buildTunnelConnectionParams( + IkeSessionParams ikeParams) { + final ChildSaProposal childProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .build(); + final TunnelModeChildSessionParams childParams = + new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); + + return new IkeTunnelConnectionParams(ikeParams, childParams); + } + + protected static IkeSessionParams.Builder getIkeSessionParamsBase() { final IkeSaProposal ikeProposal = new IkeSaProposal.Builder() .addEncryptionAlgorithm( @@ -43,23 +62,12 @@ public class VcnTestBase { final String testRemoteId = "test.server.com"; final byte[] psk = "psk".getBytes(); - final IkeSessionParams ikeParams = - new IkeSessionParams.Builder() - .setServerHostname(serverHostname) - .addSaProposal(ikeProposal) - .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) - .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) - .setAuthPsk(psk) - .build(); - - final ChildSaProposal childProposal = - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) - .build(); - final TunnelModeChildSessionParams childParams = - new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); - - return new IkeTunnelConnectionParams(ikeParams, childParams); + return new IkeSessionParams.Builder() + .setServerHostname(serverHostname) + .addSaProposal(ikeProposal) + .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) + .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) + .setAuthPsk(psk) + .addIkeOption(IKE_OPTION_MOBIKE); } } From 33e025340e5eb9506b248028f54b1ebfaffc5324 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 11 May 2021 14:50:11 -0700 Subject: [PATCH 0213/1057] Require MOBIKE for IkeSessionParams in VCN configs. This CL updates VcnGatewayConnectionConfigs to require IkeTunnelConnectionParams with MOBIKE enabled for the IkeSessionParams. This is necessary for VCNs - without it, they do not support IPsec mobility (one of the main features of the VCN). Bug: 187851560 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I94db52a8c42d9fa4681fefb8f787f006933caa18 --- .../net/vcn/VcnGatewayConnectionConfig.java | 8 ++++++++ .../vcn/VcnGatewayConnectionConfigTest.java | 19 +++++++++++++++++++ .../IkeSessionParamsUtilsTest.java | 5 +++-- .../TunnelConnectionParamsUtilsTest.java | 9 +++++++-- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index be308d01d9..2df3e6c7ec 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,6 +15,8 @@ */ package android.net.vcn; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; @@ -433,6 +435,8 @@ public final class VcnGatewayConnectionConfig { * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. * @param tunnelConnectionParams the IKE tunnel connection configuration + * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not + * configured to support MOBIKE * @see IkeTunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ @@ -441,6 +445,10 @@ public final class VcnGatewayConnectionConfig { @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); + if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) { + throw new IllegalArgumentException( + "MOBIKE must be configured for the provided IkeSessionParams"); + } mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 9410886c35..c59dcf879b 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -16,13 +16,17 @@ package android.net.vcn; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; + 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.NetworkCapabilities; +import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; import androidx.test.filters.SmallTest; @@ -119,6 +123,21 @@ public class VcnGatewayConnectionConfigTest { } } + @Test + public void testBuilderRequiresMobikeEnabled() { + try { + final IkeSessionParams ikeParams = + IkeSessionParamsUtilsTest.createBuilderMinimum() + .removeIkeOption(IKE_OPTION_MOBIKE) + .build(); + final IkeTunnelConnectionParams tunnelParams = + TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams); + new VcnGatewayConnectionConfig.Builder(GATEWAY_CONNECTION_NAME_PREFIX, tunnelParams); + fail("Expected exception due to MOBIKE not enabled"); + } catch (IllegalArgumentException e) { + } + } + @Test public void testBuilderRequiresNonEmptyExposedCaps() { try { diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 393787f1a8..f3851130c6 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -52,8 +52,8 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IkeSessionParamsUtilsTest { - // Package private for use in EncryptedTunnelParamsUtilsTest - static IkeSessionParams.Builder createBuilderMinimum() { + // Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest + public static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated. @@ -63,6 +63,7 @@ public class IkeSessionParamsUtilsTest { .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) + .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) .setAuthPsk("psk".getBytes()); } diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java index 0c8ad32b0c..f9dc9eb4d5 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java @@ -18,6 +18,7 @@ package android.net.vcn.persistablebundleutils; import static org.junit.Assert.assertEquals; +import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import androidx.test.filters.SmallTest; @@ -31,9 +32,13 @@ import org.junit.runner.RunWith; public class TunnelConnectionParamsUtilsTest { // Public for use in VcnGatewayConnectionConfigTest public static IkeTunnelConnectionParams buildTestParams() { + return buildTestParams(IkeSessionParamsUtilsTest.createBuilderMinimum().build()); + } + + // Public for use in VcnGatewayConnectionConfigTest + public static IkeTunnelConnectionParams buildTestParams(IkeSessionParams params) { return new IkeTunnelConnectionParams( - IkeSessionParamsUtilsTest.createBuilderMinimum().build(), - TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); + params, TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); } @Test From 774811edc8f935e4317b568706599fd0c2e69aaf Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 7 May 2021 10:49:27 -0700 Subject: [PATCH 0214/1057] Create test-mode for VcnConfig. This CL creates a test-mode for VcnConfig so that they will only match with Test Networks. This is necessary for CTS testing so that VCNs can run on test networks and IKE negotiations can be injected over the Test Networks. Bug: 182291467 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I5cc340e5aaa34c5de8efafa52de49185a18d4bd3 --- .../src/android/net/vcn/VcnConfig.java | 43 +++++++++++++++++-- .../android/server/VcnManagementService.java | 9 ++++ .../server/VcnManagementServiceTest.java | 23 ++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index d41c0b4fbd..caab15251f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -52,12 +52,17 @@ public final class VcnConfig implements Parcelable { private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; @NonNull private final Set mGatewayConnectionConfigs; + private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile"; + private final boolean mIsTestModeProfile; + private VcnConfig( @NonNull String packageName, - @NonNull Set gatewayConnectionConfigs) { + @NonNull Set gatewayConnectionConfigs, + boolean isTestModeProfile) { mPackageName = packageName; mGatewayConnectionConfigs = Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs)); + mIsTestModeProfile = isTestModeProfile; validate(); } @@ -77,6 +82,7 @@ public final class VcnConfig implements Parcelable { new ArraySet<>( PersistableBundleUtils.toList( gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); + mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY); validate(); } @@ -103,6 +109,15 @@ public final class VcnConfig implements Parcelable { return Collections.unmodifiableSet(mGatewayConnectionConfigs); } + /** + * Returns whether or not this VcnConfig is restricted to test networks. + * + * @hide + */ + public boolean isTestModeProfile() { + return mIsTestModeProfile; + } + /** * Serializes this object to a PersistableBundle. * @@ -119,13 +134,14 @@ public final class VcnConfig implements Parcelable { new ArrayList<>(mGatewayConnectionConfigs), VcnGatewayConnectionConfig::toPersistableBundle); result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); + result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile); return result; } @Override public int hashCode() { - return Objects.hash(mPackageName, mGatewayConnectionConfigs); + return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); } @Override @@ -136,7 +152,8 @@ public final class VcnConfig implements Parcelable { final VcnConfig rhs = (VcnConfig) other; return mPackageName.equals(rhs.mPackageName) - && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); + && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs) + && mIsTestModeProfile == rhs.mIsTestModeProfile; } // Parcelable methods @@ -172,6 +189,8 @@ public final class VcnConfig implements Parcelable { @NonNull private final Set mGatewayConnectionConfigs = new ArraySet<>(); + private boolean mIsTestModeProfile = false; + public Builder(@NonNull Context context) { Objects.requireNonNull(context, "context was null"); @@ -206,6 +225,22 @@ public final class VcnConfig implements Parcelable { return this; } + /** + * Restricts this VcnConfig to matching with test networks (only). + * + *

      This method is for testing only, and must not be used by apps. Calling {@link + * VcnManager#setVcnConfig(ParcelUuid, VcnConfig)} with a VcnConfig where test-network usage + * is enabled will require the MANAGE_TEST_NETWORKS permission. + * + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setIsTestModeProfile() { + mIsTestModeProfile = true; + return this; + } + /** * Builds and validates the VcnConfig. * @@ -213,7 +248,7 @@ public final class VcnConfig implements Parcelable { */ @NonNull public VcnConfig build() { - return new VcnConfig(mPackageName, mGatewayConnectionConfigs); + return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); } } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 471d2af278..f274305d31 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -421,6 +421,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Carrier privilege required for subscription group to set VCN Config"); } + private void enforceManageTestNetworksForTestMode(@NonNull VcnConfig vcnConfig) { + if (vcnConfig.isTestModeProfile()) { + mContext.enforceCallingPermission( + android.Manifest.permission.MANAGE_TEST_NETWORKS, + "Test-mode require the MANAGE_TEST_NETWORKS permission"); + } + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -588,6 +596,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); + enforceManageTestNetworksForTestMode(config); enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 9ecd82ff6b..8d87348ac4 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -66,6 +66,7 @@ import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.IBinder; @@ -527,6 +528,28 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testSetVcnConfigTestModeRequiresPermission() throws Exception { + doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS")) + .when(mMockContext) + .enforceCallingPermission( + eq(android.Manifest.permission.MANAGE_TEST_NETWORKS), any()); + + final VcnConfig vcnConfig = + new VcnConfig.Builder(mMockContext) + .addGatewayConnectionConfig( + VcnGatewayConnectionConfigTest.buildTestConfig()) + .setIsTestModeProfile() + .build(); + + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME); + fail("Expected exception due to using test-mode without permission"); + } catch (SecurityException e) { + verify(mMockPolicyListener, never()).onPolicyChanged(); + } + } + @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); From 1445dfea86a9bf1d9cf01c3623b1d65c57bfab4b Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 7 May 2021 15:48:46 -0700 Subject: [PATCH 0215/1057] Specify if a VCN is in 'test-mode' in VcnContext. This CL updates VcnContext to include whether the VCN instance it is created for is in test-mode (as specified by the VcnConfig). This also changes the lifetime of VcnContext to be created uniquely for each VCN instance (as opposed to a single VcnContext created in VcnManagementService and used for all VCNs). Bug: 182291467 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I6fc6a266bf67ab2aa64202153c3c109ee98a16ca --- .../src/com/android/server/VcnManagementService.java | 12 +++++++----- .../src/com/android/server/vcn/VcnContext.java | 9 ++++++++- .../com/android/server/VcnManagementServiceTest.java | 10 +++++++++- .../server/vcn/UnderlyingNetworkTrackerTest.java | 8 +++++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f274305d31..b49b77c899 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -167,7 +167,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnNetworkProvider mNetworkProvider; @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; - @NonNull private final VcnContext mVcnContext; @NonNull private final BroadcastReceiver mPkgChangeReceiver; @NonNull @@ -212,7 +211,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext, mLooper, mTelephonySubscriptionTrackerCb); mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); - mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider); mPkgChangeReceiver = new BroadcastReceiver() { @Override @@ -336,8 +334,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { public VcnContext newVcnContext( @NonNull Context context, @NonNull Looper looper, - @NonNull VcnNetworkProvider vcnNetworkProvider) { - return new VcnContext(context, looper, vcnNetworkProvider); + @NonNull VcnNetworkProvider vcnNetworkProvider, + boolean getIsInTestMode) { + return new VcnContext(context, looper, vcnNetworkProvider, getIsInTestMode); } /** Creates a new Vcn instance using the provided configuration */ @@ -551,8 +550,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); + final VcnContext vcnContext = + mDeps.newVcnContext( + mContext, mLooper, mNetworkProvider, config.isTestModeProfile()); final Vcn newInstance = - mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback); + mDeps.newVcn(vcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback); mVcns.put(subscriptionGroup, newInstance); // Now that a new VCN has started, notify all registered listeners to refresh their diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 7399e56b3a..d958222ea4 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -31,14 +31,17 @@ public class VcnContext { @NonNull private final Context mContext; @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + private final boolean mIsInTestMode; public VcnContext( @NonNull Context context, @NonNull Looper looper, - @NonNull VcnNetworkProvider vcnNetworkProvider) { + @NonNull VcnNetworkProvider vcnNetworkProvider, + boolean isInTestMode) { mContext = Objects.requireNonNull(context, "Missing context"); mLooper = Objects.requireNonNull(looper, "Missing looper"); mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider"); + mIsInTestMode = isInTestMode; } @NonNull @@ -56,6 +59,10 @@ public class VcnContext { return mVcnNetworkProvider; } + public boolean isInTestMode() { + return mIsInTestMode; + } + /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 8d87348ac4..3360d40062 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -198,7 +199,8 @@ public class VcnManagementServiceTest { .newVcnContext( eq(mMockContext), eq(mTestLooper.getLooper()), - any(VcnNetworkProvider.class)); + any(VcnNetworkProvider.class), + anyBoolean()); doReturn(mSubscriptionTracker) .when(mMockDeps) .newTelephonySubscriptionTracker( @@ -371,6 +373,12 @@ public class VcnManagementServiceTest { public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + verify(mMockDeps) + .newVcnContext( + eq(mMockContext), + eq(mTestLooper.getLooper()), + any(VcnNetworkProvider.class), + anyBoolean()); verify(mMockDeps) .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 8289e85dad..2fc4309d49 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -112,7 +112,13 @@ public class UnderlyingNetworkTrackerTest { MockitoAnnotations.initMocks(this); mTestLooper = new TestLooper(); - mVcnContext = spy(new VcnContext(mContext, mTestLooper.getLooper(), mVcnNetworkProvider)); + mVcnContext = + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); setupSystemService( From 6e3dadc2dcc8225ba543506120c336677ef9095b Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 7 May 2021 16:58:34 -0700 Subject: [PATCH 0216/1057] Request Test Networks for VCNs when in Test Mode. This CL updates UnderlyingNetworkTracker to request Test Networks for route selection when the VCN it is tracking for is in test-mode. Bug: 182291467 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Icb59b15df61ec43fe76e250977a985caa6a1dffc --- .../server/vcn/UnderlyingNetworkTracker.java | 17 +++++++ .../vcn/UnderlyingNetworkTrackerTest.java | 49 +++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 88180239da..3c6bb647c5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -158,8 +158,15 @@ public class UnderlyingNetworkTracker { * carrier owned networks may be selected, as the request specifies only subIds in the VCN's * subscription group, while the VCN networks are excluded by virtue of not having subIds set on * the VCN-exposed networks. + * + *

      If the VCN that this UnderlyingNetworkTracker belongs to is in test-mode, this will return + * a NetworkRequest that only matches Test Networks. */ private NetworkRequest getRouteSelectionRequest() { + if (mVcnContext.isInTestMode()) { + return getTestNetworkRequest(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); + } + return getBaseNetworkRequestBuilder() .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); @@ -210,6 +217,16 @@ public class UnderlyingNetworkTracker { .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } + /** Builds and returns a NetworkRequest for the given subIds to match Test Networks. */ + private NetworkRequest getTestNetworkRequest(@NonNull Set subIds) { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .setSubscriptionIds(subIds) + .build(); + } + /** * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 2fc4309d49..6f63c4b2e1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -119,7 +120,7 @@ public class UnderlyingNetworkTrackerTest { mTestLooper.getLooper(), mVcnNetworkProvider, false /* isInTestMode */)); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + resetVcnContext(); setupSystemService( mContext, @@ -138,6 +139,11 @@ public class UnderlyingNetworkTrackerTest { mNetworkTrackerCb); } + private void resetVcnContext() { + reset(mVcnContext); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + } + private static LinkProperties getLinkPropertiesWithName(String iface) { LinkProperties linkProperties = new LinkProperties(); linkProperties.setInterfaceName(iface); @@ -155,7 +161,29 @@ public class UnderlyingNetworkTrackerTest { verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); } + @Test + public void testNetworkCallbacksRegisteredOnStartupForTestMode() { + resetVcnContext(); + when(mVcnContext.isInTestMode()).thenReturn(true); + reset(mConnectivityManager); + + mUnderlyingNetworkTracker = + new UnderlyingNetworkTracker( + mVcnContext, + SUB_GROUP, + mSubscriptionSnapshot, + Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), + mNetworkTrackerCb); + + verifyNetworkRequestsRegistered(INITIAL_SUB_IDS, true /* expectTestMode */); + } + private void verifyNetworkRequestsRegistered(Set expectedSubIds) { + verifyNetworkRequestsRegistered(expectedSubIds, false /* expectTestMode */); + } + + private void verifyNetworkRequestsRegistered( + Set expectedSubIds, boolean expectTestMode) { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getWifiRequest(expectedSubIds)), @@ -168,10 +196,16 @@ public class UnderlyingNetworkTrackerTest { any(NetworkBringupCallback.class), any()); } + final NetworkRequest expectedRouteSelectionRequest = + expectTestMode + ? getTestNetworkRequest(expectedSubIds) + : getRouteSelectionRequest(expectedSubIds); + verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getRouteSelectionRequest(expectedSubIds)), - any(RouteSelectionCallback.class), any()); + eq(expectedRouteSelectionRequest), + any(RouteSelectionCallback.class), + any()); } @Test @@ -210,6 +244,15 @@ public class UnderlyingNetworkTrackerTest { return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); } + private NetworkRequest getTestNetworkRequest(Set netCapsSubIds) { + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .setSubscriptionIds(netCapsSubIds) + .build(); + } + private NetworkRequest.Builder getExpectedRequestBase() { final NetworkRequest.Builder builder = new NetworkRequest.Builder() From 265664270d4a4111af349f6ec935dd52430085d8 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 11 May 2021 18:34:51 -0700 Subject: [PATCH 0217/1057] Correct variable name in VcnManagementService. Bug: 182291467 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: If4fcaa523e5cac85c916f7c41cef996129652a5d --- .../src/com/android/server/VcnManagementService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index b49b77c899..34d8a46842 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -335,8 +335,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull Context context, @NonNull Looper looper, @NonNull VcnNetworkProvider vcnNetworkProvider, - boolean getIsInTestMode) { - return new VcnContext(context, looper, vcnNetworkProvider, getIsInTestMode); + boolean isInTestMode) { + return new VcnContext(context, looper, vcnNetworkProvider, isInTestMode); } /** Creates a new Vcn instance using the provided configuration */ From ba5f144cfa58dcb633b663d6ae6e96d552a7ac7a Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 11 May 2021 19:17:54 -0700 Subject: [PATCH 0218/1057] Restructure Test Network requests for VCN connections. This CL restructures the NetworkRequests used for TestNetworks in UnderlyingNetworkTracker to clearly show that they only require TRANSPORT_TEST and the relevant subIds. Bug: 182291467 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I4b135749fdde9f91c66b87b1ded921700e6440fd --- .../server/vcn/UnderlyingNetworkTracker.java | 5 ++- .../vcn/UnderlyingNetworkTrackerTest.java | 35 +++++++++---------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 3c6bb647c5..3bdeec0c1d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -219,10 +219,9 @@ public class UnderlyingNetworkTracker { /** Builds and returns a NetworkRequest for the given subIds to match Test Networks. */ private NetworkRequest getTestNetworkRequest(@NonNull Set subIds) { - return getBaseNetworkRequestBuilder() + return new NetworkRequest.Builder() + .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .setSubscriptionIds(subIds) .build(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 6f63c4b2e1..0b72cd93e8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -163,27 +163,30 @@ public class UnderlyingNetworkTrackerTest { @Test public void testNetworkCallbacksRegisteredOnStartupForTestMode() { - resetVcnContext(); - when(mVcnContext.isInTestMode()).thenReturn(true); - reset(mConnectivityManager); + final VcnContext vcnContext = + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */)); mUnderlyingNetworkTracker = new UnderlyingNetworkTracker( - mVcnContext, + vcnContext, SUB_GROUP, mSubscriptionSnapshot, Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); - verifyNetworkRequestsRegistered(INITIAL_SUB_IDS, true /* expectTestMode */); + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getTestNetworkRequest(INITIAL_SUB_IDS)), + any(RouteSelectionCallback.class), + any()); } private void verifyNetworkRequestsRegistered(Set expectedSubIds) { - verifyNetworkRequestsRegistered(expectedSubIds, false /* expectTestMode */); - } - - private void verifyNetworkRequestsRegistered( - Set expectedSubIds, boolean expectTestMode) { verify(mConnectivityManager) .requestBackgroundNetwork( eq(getWifiRequest(expectedSubIds)), @@ -196,14 +199,9 @@ public class UnderlyingNetworkTrackerTest { any(NetworkBringupCallback.class), any()); } - final NetworkRequest expectedRouteSelectionRequest = - expectTestMode - ? getTestNetworkRequest(expectedSubIds) - : getRouteSelectionRequest(expectedSubIds); - verify(mConnectivityManager) .requestBackgroundNetwork( - eq(expectedRouteSelectionRequest), + eq(getRouteSelectionRequest(expectedSubIds)), any(RouteSelectionCallback.class), any()); } @@ -245,10 +243,9 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getTestNetworkRequest(Set netCapsSubIds) { - return getExpectedRequestBase() + return new NetworkRequest.Builder() + .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .setSubscriptionIds(netCapsSubIds) .build(); } From 97c2cf2a815808281ffabccfe555a895d698ec2d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 10 May 2021 10:19:11 +0900 Subject: [PATCH 0219/1057] Immediately redact VcnTransportInfo. Redaction of NetworkCapabilities is changing from redacting at parcel time to redacting immediately when makeCopy() is called. Update VcnTransportInfo redaction accordingly. Bug: 183938194 Test: atest VcnTransportInfoTest Change-Id: I0c9406f426b66fd36b47d11799955def531c16ba --- .../src/android/net/vcn/VcnTransportInfo.java | 76 +++---------------- .../android/net/vcn/VcnTransportInfoTest.java | 57 ++++++-------- 2 files changed, 35 insertions(+), 98 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 0e9ccf144c..1f1818420b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -16,23 +16,17 @@ package android.net.vcn; -import static android.net.NetworkCapabilities.REDACT_ALL; -import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionManager; -import com.android.internal.annotations.VisibleForTesting; - import java.util.Objects; /** @@ -55,32 +49,17 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; - /** - * The redaction scheme to use when parcelling. - * - *

      The TransportInfo/NetworkCapabilities redaction mechanisms rely on redaction being - * performed at parcelling time. This means that the redaction scheme must be stored for later - * use. - * - *

      Since the redaction scheme itself is not parcelled, this field is listed as a transient. - * - *

      Defaults to REDACT_ALL when constructed using public constructors, or creating from - * parcels. - */ - private final transient long mRedactions; - public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, INVALID_SUBSCRIPTION_ID, REDACT_ALL); + this(wifiInfo, INVALID_SUBSCRIPTION_ID); } public VcnTransportInfo(int subId) { - this(null /* wifiInfo */, subId, REDACT_ALL); + this(null /* wifiInfo */, subId); } - private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId, long redactions) { + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { mWifiInfo = wifiInfo; mSubId = subId; - mRedactions = redactions; } /** @@ -102,25 +81,14 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. * * @return the Subscription ID if a cellular underlying Network is present, else {@link - * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}. + * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. */ public int getSubId() { return mSubId; } - /** - * Gets the redaction scheme - * - * @hide - */ - @VisibleForTesting(visibility = PRIVATE) - public long getRedaction() { - return mRedactions; - } - @Override public int hashCode() { - // mRedactions not hashed, as it is a transient, for control of parcelling return Objects.hash(mWifiInfo, mSubId); } @@ -128,8 +96,6 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public boolean equals(Object o) { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; - - // mRedactions not compared, as it is a transient, for control of parcelling return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; } @@ -143,31 +109,19 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @NonNull public TransportInfo makeCopy(long redactions) { return new VcnTransportInfo( - mWifiInfo == null ? null : mWifiInfo.makeCopy(redactions), mSubId, redactions); + (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId); } @Override public long getApplicableRedactions() { - long redactions = REDACT_FOR_NETWORK_SETTINGS; - - // Add additional wifi redactions if necessary - if (mWifiInfo != null) { - redactions |= mWifiInfo.getApplicableRedactions(); - } - - return redactions; - } - - private boolean shouldParcelNetworkSettingsFields() { - return (mRedactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) == 0; + return (mWifiInfo == null) ? REDACT_NONE : mWifiInfo.getApplicableRedactions(); } /** {@inheritDoc} */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(shouldParcelNetworkSettingsFields() ? mSubId : INVALID_SUBSCRIPTION_ID); - dest.writeParcelable( - shouldParcelNetworkSettingsFields() ? (Parcelable) mWifiInfo : null, flags); + dest.writeInt(mSubId); + dest.writeParcelable(mWifiInfo, flags); } @Override @@ -181,17 +135,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); final WifiInfo wifiInfo = in.readParcelable(null); - - // If all fields are their null values, return null TransportInfo to avoid - // leaking information about this being a VCN Network (instead of macro - // cellular, etc) - if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { - return null; - } - - // Prevent further forwarding by redacting everything in future parcels from - // this VcnTransportInfo - return new VcnTransportInfo(wifiInfo, subId, REDACT_ALL); + return new VcnTransportInfo(wifiInfo, subId); } public VcnTransportInfo[] newArray(int size) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 582275d054..00a0bffa15 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -16,14 +16,17 @@ package android.net.vcn; -import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.Parcel; @@ -38,12 +41,6 @@ public class VcnTransportInfoTest { private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); - @Test - public void testRedactionDefaults() { - assertEquals(REDACT_ALL, CELL_UNDERLYING_INFO.getRedaction()); - assertEquals(REDACT_ALL, WIFI_UNDERLYING_INFO.getRedaction()); - } - @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); @@ -59,15 +56,15 @@ public class VcnTransportInfoTest { } @Test - public void testMakeCopySetsRedactions() { + public void testMakeCopyRedactForAccessFineLocation() { assertEquals( - REDACT_FOR_NETWORK_SETTINGS, - ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) - .getRedaction()); + SUB_ID, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getSubId()); assertEquals( - REDACT_FOR_NETWORK_SETTINGS, - ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) - .getRedaction()); + WifiConfiguration.INVALID_NETWORK_ID, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getWifiInfo().getNetworkId()); } @Test @@ -78,35 +75,31 @@ public class VcnTransportInfoTest { } @Test - public void testParcelUnparcel() { - verifyParcelingIsNull(CELL_UNDERLYING_INFO); - verifyParcelingIsNull(WIFI_UNDERLYING_INFO); - } - - private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { - // Verify redacted by default - Parcel parcel = Parcel.obtain(); - vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); - parcel.setDataPosition(0); - - assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); + public void testApplicableRedactions() { + assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions()); + assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS + | REDACT_FOR_NETWORK_SETTINGS, + WIFI_UNDERLYING_INFO.getApplicableRedactions()); } @Test - public void testParcelUnparcelNotRedactedForSysUi() { - verifyParcelingForSysUi(CELL_UNDERLYING_INFO); - verifyParcelingForSysUi(WIFI_UNDERLYING_INFO); + public void testParcelNotRedactedForSysUi() { + VcnTransportInfo cellRedacted = parcelForSysUi(CELL_UNDERLYING_INFO); + assertEquals(SUB_ID, cellRedacted.getSubId()); + VcnTransportInfo wifiRedacted = parcelForSysUi(WIFI_UNDERLYING_INFO); + assertEquals(NETWORK_ID, wifiRedacted.getWifiInfo().getNetworkId()); } - private void verifyParcelingForSysUi(VcnTransportInfo vcnTransportInfo) { + private VcnTransportInfo parcelForSysUi(VcnTransportInfo vcnTransportInfo) { // Allow fully unredacted; SysUI will have all the relevant permissions. - final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(0); + final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy( + REDACT_NONE); final Parcel parcel = Parcel.obtain(); unRedacted.writeToParcel(parcel, 0 /* flags */); parcel.setDataPosition(0); final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel); assertEquals(vcnTransportInfo, unparceled); - assertEquals(REDACT_ALL, unparceled.getRedaction()); + return unparceled; } } From 4db00ee3ac584187bc8b7c9bc6b9f295c254b729 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 13 May 2021 17:20:10 +0900 Subject: [PATCH 0220/1057] Make VcnTransportInfoTest pass on AOSP. AOSP contains the core networking redaction changes, but not the wifi redaction changes, so the tests that depend on wifi S behaviour will not pass on AOSP. Fix testApplicableRedactions by checking that the applicable redactions are the same ones as returned by the underlying WifiInfo object. Fix testMakeCopyRedactForAccessFineLocation by testing the wifi redaction code iff Build.VERSION.SDK_INT is S or later. This is different from SdkLevel.isAtLeastS, because the latter returns true in AOSP. Bug: 183938194 Test: atest VcnTransportInfoTest Change-Id: Ia5bc896c92be19f570638f8051492e0f2d7342f9 --- .../android/net/vcn/VcnTransportInfoTest.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 00a0bffa15..abae81cf17 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -17,8 +17,6 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; -import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; -import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -28,6 +26,7 @@ import static org.junit.Assert.assertNull; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.os.Build; import android.os.Parcel; import org.junit.Test; @@ -61,10 +60,14 @@ public class VcnTransportInfoTest { SUB_ID, ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) .getSubId()); - assertEquals( - WifiConfiguration.INVALID_NETWORK_ID, - ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) - .getWifiInfo().getNetworkId()); + + // TODO: remove the if statement when S pushes to AOSP. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + assertEquals( + WifiConfiguration.INVALID_NETWORK_ID, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy( + REDACT_FOR_ACCESS_FINE_LOCATION)).getWifiInfo().getNetworkId()); + } } @Test @@ -77,9 +80,9 @@ public class VcnTransportInfoTest { @Test public void testApplicableRedactions() { assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions()); - assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS - | REDACT_FOR_NETWORK_SETTINGS, - WIFI_UNDERLYING_INFO.getApplicableRedactions()); + + final long wifiRedactions = WIFI_INFO.getApplicableRedactions(); + assertEquals(wifiRedactions, WIFI_UNDERLYING_INFO.getApplicableRedactions()); } @Test From 855c752cc4ee4b9e685b2846572bc6f5e00af2e9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 10 May 2021 10:15:15 -0700 Subject: [PATCH 0221/1057] Custom network selection This change adds a basic prioritization framework in the VCN, and signal strength thresholds for WiFi. Bug: 188104094 Test: atest FrameworksVcnTests Change-Id: Iee4e3dbecf1102ddc127a8c8daf08a00b6fccbbd --- .../src/android/net/vcn/VcnManager.java | 30 ++ .../vcn/TelephonySubscriptionTracker.java | 38 +- .../server/vcn/UnderlyingNetworkTracker.java | 447 ++++++++++++++---- .../vcn/TelephonySubscriptionTrackerTest.java | 20 +- .../vcn/UnderlyingNetworkTrackerTest.java | 125 +++-- .../vcn/VcnGatewayConnectionTestBase.java | 9 +- 6 files changed, 520 insertions(+), 149 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 9d1c1ff898..390c3b9453 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -74,6 +74,36 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + /** + * Key for WiFi entry RSSI thresholds + * + *

      The VCN will only migrate to a Carrier WiFi network that has a signal strength greater + * than, or equal to this threshold. + * + *

      WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_entry_rssi_threshold"; + + /** + * Key for WiFi entry RSSI thresholds + * + *

      If the VCN's selected Carrier WiFi network has a signal strength less than this threshold, + * the VCN will attempt to migrate away from the Carrier WiFi network. + * + *

      WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_exit_rssi_threshold"; + + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz + private static final Map< VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 19fbdbd860..5565ccb6cf 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -145,7 +145,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { */ public void handleSubscriptionsChanged() { final Map> privilegedPackages = new HashMap<>(); - final Map newSubIdToGroupMap = new HashMap<>(); + final Map newSubIdToInfoMap = new HashMap<>(); final List allSubs = mSubscriptionManager.getAllSubscriptionInfoList(); if (allSubs == null) { @@ -160,7 +160,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } // Build subId -> subGrp cache - newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid()); + newSubIdToInfoMap.put(subInfo.getSubscriptionId(), subInfo); // Update subscription groups that are both ready, and active. For a group to be // considered active, both of the following must be true: @@ -186,7 +186,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToGroupMap, privilegedPackages); + new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -245,7 +245,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { - private final Map mSubIdToGroupMap; + private final Map mSubIdToInfoMap; private final Map> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = @@ -253,12 +253,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( - @NonNull Map subIdToGroupMap, + @NonNull Map subIdToInfoMap, @NonNull Map> privilegedPackages) { - Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"); + Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); - mSubIdToGroupMap = Collections.unmodifiableMap(subIdToGroupMap); + mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap); final Map> unmodifiableInnerSets = new ArrayMap<>(); for (Entry> entry : privilegedPackages.entrySet()) { @@ -285,7 +285,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Returns the Subscription Group for a given subId. */ @Nullable public ParcelUuid getGroupForSubId(int subId) { - return mSubIdToGroupMap.get(subId); + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).getGroupUuid() + : null; } /** @@ -295,8 +297,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public Set getAllSubIdsInGroup(ParcelUuid subGrp) { final Set subIds = new ArraySet<>(); - for (Entry entry : mSubIdToGroupMap.entrySet()) { - if (subGrp.equals(entry.getValue())) { + for (Entry entry : mSubIdToInfoMap.entrySet()) { + if (subGrp.equals(entry.getValue().getGroupUuid())) { subIds.add(entry.getKey()); } } @@ -304,9 +306,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return subIds; } + /** Checks if the requested subscription is opportunistic */ + @NonNull + public boolean isOpportunistic(int subId) { + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).isOpportunistic() + : false; + } + @Override public int hashCode() { - return Objects.hash(mSubIdToGroupMap, mPrivilegedPackages); + return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -317,7 +327,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToGroupMap.equals(other.mSubIdToGroupMap) + return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -326,7 +336,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); - pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap); + pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); pw.decreaseIndent(); @@ -335,7 +345,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToGroupMap=" + mSubIdToGroupMap + + "mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 3bdeec0c1d..fb4c6236a9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -16,6 +16,10 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; @@ -25,8 +29,16 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -35,9 +47,13 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; /** * Tracks a set of Networks underpinning a VcnGatewayConnection. @@ -51,6 +67,45 @@ import java.util.Set; public class UnderlyingNetworkTracker { @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); + /** + * Minimum signal strength for a WiFi network to be eligible for switching to + * + *

      A network that satisfies this is eligible to become the selected underlying network with + * no additional conditions + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70; + + /** + * Minimum signal strength to continue using a WiFi network + * + *

      A network that satisfies the conditions may ONLY continue to be used if it is already + * selected as the underlying network. A WiFi network satisfying this condition, but NOT the + * prospective-network RSSI threshold CANNOT be switched to. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; + + /** Priority for any cellular network for which the subscription is listed as opportunistic */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0; + + /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_IN_USE = 1; + + /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_PROSPECTIVE = 2; + + /** Priority for any standard macro cellular network */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_MACRO_CELLULAR = 3; + + /** Priority for any other networks (including unvalidated, etc) */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_ANY = Integer.MAX_VALUE; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; @@ -58,12 +113,17 @@ public class UnderlyingNetworkTracker { @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; + @NonNull private final TelephonyCallback mActiveDataSubIdListener = + new VcnActiveDataSubscriptionIdListener(); @NonNull private final List mCellBringupCallbacks = new ArrayList<>(); @Nullable private NetworkCallback mWifiBringupCallback; - @Nullable private NetworkCallback mRouteSelectionCallback; + @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback; + @Nullable private NetworkCallback mWifiExitRssiThresholdCallback; + @Nullable private UnderlyingNetworkListener mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; + @Nullable private PersistableBundle mCarrierConfig; private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @@ -104,6 +164,30 @@ public class UnderlyingNetworkTracker { mHandler = new Handler(mVcnContext.getLooper()); mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .registerTelephonyCallback(new HandlerExecutor(mHandler), mActiveDataSubIdListener); + + // TODO: Listen for changes in carrier config that affect this. + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + PersistableBundle config = + mVcnContext + .getContext() + .getSystemService(CarrierConfigManager.class) + .getConfigForSubId(subId); + + if (config != null) { + mCarrierConfig = config; + + // Attempt to use (any) non-opportunistic subscription. If this subscription is + // opportunistic, continue and try to find a non-opportunistic subscription, using + // the opportunistic ones as a last resort. + if (!isOpportunistic(mLastSnapshot, Collections.singleton(subId))) { + break; + } + } + } registerOrUpdateNetworkRequests(); } @@ -111,16 +195,30 @@ public class UnderlyingNetworkTracker { private void registerOrUpdateNetworkRequests() { NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; NetworkCallback oldWifiCallback = mWifiBringupCallback; + NetworkCallback oldWifiEntryRssiThresholdCallback = mWifiEntryRssiThresholdCallback; + NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback; List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); // Register new callbacks. Make-before-break; always register new callbacks before removal // of old callbacks if (!mIsQuitting) { - mRouteSelectionCallback = new RouteSelectionCallback(); - mConnectivityManager.requestBackgroundNetwork( + mRouteSelectionCallback = new UnderlyingNetworkListener(); + mConnectivityManager.registerNetworkCallback( getRouteSelectionRequest(), mRouteSelectionCallback, mHandler); + mWifiEntryRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiEntryRssiThresholdNetworkRequest(), + mWifiEntryRssiThresholdCallback, + mHandler); + + mWifiExitRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiExitRssiThresholdNetworkRequest(), + mWifiExitRssiThresholdCallback, + mHandler); + mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( getWifiNetworkRequest(), mWifiBringupCallback, mHandler); @@ -135,6 +233,8 @@ public class UnderlyingNetworkTracker { } else { mRouteSelectionCallback = null; mWifiBringupCallback = null; + mWifiEntryRssiThresholdCallback = null; + mWifiExitRssiThresholdCallback = null; // mCellBringupCallbacks already cleared above. } @@ -145,6 +245,12 @@ public class UnderlyingNetworkTracker { if (oldWifiCallback != null) { mConnectivityManager.unregisterNetworkCallback(oldWifiCallback); } + if (oldWifiEntryRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiEntryRssiThresholdCallback); + } + if (oldWifiExitRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiExitRssiThresholdCallback); + } for (NetworkCallback cellBringupCallback : oldCellCallbacks) { mConnectivityManager.unregisterNetworkCallback(cellBringupCallback); } @@ -168,6 +274,8 @@ public class UnderlyingNetworkTracker { } return getBaseNetworkRequestBuilder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } @@ -188,6 +296,38 @@ public class UnderlyingNetworkTracker { .build(); } + /** + * Builds the WiFi entry threshold signal strength request + * + *

      This request ensures that WiFi reports the crossing of the wifi entry RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select a short-lived WiFi offload network. + */ + private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig)) + .build(); + } + + /** + * Builds the WiFi exit threshold signal strength request + * + *

      This request ensures that WiFi reports the crossing of the wifi exit RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select away from a failing WiFi network. + */ + private NetworkRequest getWifiExitRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig)) + .build(); + } + /** * Builds a Cellular bringup request for a given subId * @@ -233,10 +373,18 @@ public class UnderlyingNetworkTracker { * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change. */ - public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { - Objects.requireNonNull(snapshot, "Missing snapshot"); + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot newSnapshot) { + Objects.requireNonNull(newSnapshot, "Missing newSnapshot"); - mLastSnapshot = snapshot; + final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; + mLastSnapshot = newSnapshot; + + // Only trigger re-registration if subIds in this group have changed + if (oldSnapshot + .getAllSubIdsInGroup(mSubscriptionGroup) + .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { + return; + } registerOrUpdateNetworkRequests(); } @@ -247,88 +395,43 @@ public class UnderlyingNetworkTracker { // Will unregister all existing callbacks, but not register new ones due to quitting flag. registerOrUpdateNetworkRequests(); + + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .unregisterTelephonyCallback(mActiveDataSubIdListener); } - /** Returns whether the currently selected Network matches the given network. */ - private static boolean isSameNetwork( - @Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) { - return recordInProgress != null && recordInProgress.getNetwork().equals(network); - } + private void reevaluateNetworks() { + TreeSet sorted = + new TreeSet<>( + UnderlyingNetworkRecord.getComparator( + mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig)); + sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks()); - /** Notify the Callback if a full UnderlyingNetworkRecord exists. */ - private void maybeNotifyCallback() { - // Only forward this update if a complete record has been received - if (!mRecordInProgress.isValid()) { + UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); + if (Objects.equals(mCurrentRecord, candidate)) { return; } - // Only forward this update if the updated record differs form the current record - UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build(); - if (!updatedRecord.equals(mCurrentRecord)) { - mCurrentRecord = updatedRecord; - - mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); - } + mCurrentRecord = candidate; + mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); } - private void handleNetworkAvailable(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - mRecordInProgress = new UnderlyingNetworkRecord.Builder(network); - } - - private void handleNetworkLost(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Non-underlying Network lost"); - return; + private static boolean isOpportunistic( + @NonNull TelephonySubscriptionSnapshot snapshot, Set subIds) { + if (snapshot == null) { + Slog.wtf(TAG, "Got null snapshot"); + return false; } - mRecordInProgress = null; - mCurrentRecord = null; - mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */); - } - - private void handleCapabilitiesChanged( - @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to NetworkCapabilities"); - return; + for (int subId : subIds) { + if (snapshot.isOpportunistic(subId)) { + return true; + } } - mRecordInProgress.setNetworkCapabilities(networkCapabilities); - - maybeNotifyCallback(); - } - - private void handlePropertiesChanged( - @NonNull Network network, @NonNull LinkProperties linkProperties) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to LinkProperties"); - return; - } - - mRecordInProgress.setLinkProperties(linkProperties); - - maybeNotifyCallback(); - } - - private void handleNetworkBlocked(@NonNull Network network, boolean isBlocked) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to isBlocked"); - return; - } - - mRecordInProgress.setIsBlocked(isBlocked); - - maybeNotifyCallback(); + return false; } /** @@ -347,36 +450,104 @@ public class UnderlyingNetworkTracker { * truth. */ @VisibleForTesting - class RouteSelectionCallback extends NetworkCallback { + class UnderlyingNetworkListener extends NetworkCallback { + private final Map + mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); + + private List getUnderlyingNetworks() { + final List records = new ArrayList<>(); + + for (UnderlyingNetworkRecord.Builder builder : + mUnderlyingNetworkRecordBuilders.values()) { + if (builder.isValid()) { + records.add(builder.build()); + } + } + + return records; + } + @Override public void onAvailable(@NonNull Network network) { - handleNetworkAvailable(network); + mUnderlyingNetworkRecordBuilders.put( + network, new UnderlyingNetworkRecord.Builder(network)); } @Override public void onLost(@NonNull Network network) { - handleNetworkLost(network); + mUnderlyingNetworkRecordBuilders.remove(network); + + reevaluateNetworks(); } @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return; - handleCapabilitiesChanged(network, networkCapabilities); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got capabilities change for unknown key: " + network); + return; + } + + builder.setNetworkCapabilities(networkCapabilities); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { - handlePropertiesChanged(network, linkProperties); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got link properties change for unknown key: " + network); + return; + } + + builder.setLinkProperties(linkProperties); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { - handleNetworkBlocked(network, isBlocked); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got blocked status change for unknown key: " + network); + return; + } + + builder.setIsBlocked(isBlocked); + if (builder.isValid()) { + reevaluateNetworks(); + } } } + private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT); + } + + return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; + } + + private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + WIFI_EXIT_RSSI_THRESHOLD_DEFAULT); + } + + return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; + } + /** A record of a single underlying network, caching relevant fields. */ public static class UnderlyingNetworkRecord { @NonNull public final Network network; @@ -413,6 +584,89 @@ public class UnderlyingNetworkTracker { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } + /** + * Gives networks a priority class, based on the following priorities: + * + *

        + *
      1. Opportunistic cellular + *
      2. Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT + *
      3. Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT + *
      4. Macro cellular + *
      5. Any others + *
      + */ + private int calculatePriorityClass( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkCapabilities; + + // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED + + if (isBlocked) { + Slog.wtf(TAG, "Network blocked for System Server: " + network); + return PRIORITY_ANY; + } + + if (caps.hasTransport(TRANSPORT_CELLULAR) + && isOpportunistic(snapshot, caps.getSubscriptionIds())) { + // If this carrier is the active data provider, ensure that opportunistic is only + // ever prioritized if it is also the active data subscription. This ensures that + // if an opportunistic subscription is still in the process of being switched to, + // or switched away from, the VCN does not attempt to continue using it against the + // decision made at the telephony layer. Failure to do so may result in the modem + // switching back and forth. + // + // Allow the following two cases: + // 1. Active subId is NOT in the group that this VCN is supporting + // 2. This opportunistic subscription is for the active subId + if (!snapshot.getAllSubIdsInGroup(subscriptionGroup) + .contains(SubscriptionManager.getActiveDataSubscriptionId()) + || caps.getSubscriptionIds() + .contains(SubscriptionManager.getActiveDataSubscriptionId())) { + return PRIORITY_OPPORTUNISTIC_CELLULAR; + } + } + + if (caps.hasTransport(TRANSPORT_WIFI)) { + if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) + && currentlySelected != null + && network.equals(currentlySelected.network)) { + return PRIORITY_WIFI_IN_USE; + } + + if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { + return PRIORITY_WIFI_PROSPECTIVE; + } + } + + // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might + // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be + // the case if the Default Data SubId does not support certain services (eg voice + // calling) + if (caps.hasTransport(TRANSPORT_CELLULAR) + && !isOpportunistic(snapshot, caps.getSubscriptionIds())) { + return PRIORITY_MACRO_CELLULAR; + } + + return PRIORITY_ANY; + } + + private static Comparator getComparator( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + return (left, right) -> { + return Integer.compare( + left.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig), + right.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig)); + }; + } + /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkRecord:"); @@ -434,6 +688,8 @@ public class UnderlyingNetworkTracker { boolean mIsBlocked; boolean mWasIsBlockedSet; + @Nullable private UnderlyingNetworkRecord mCached; + private Builder(@NonNull Network network) { mNetwork = network; } @@ -445,6 +701,7 @@ public class UnderlyingNetworkTracker { private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { mNetworkCapabilities = networkCapabilities; + mCached = null; } @Nullable @@ -454,11 +711,13 @@ public class UnderlyingNetworkTracker { private void setLinkProperties(@NonNull LinkProperties linkProperties) { mLinkProperties = linkProperties; + mCached = null; } private void setIsBlocked(boolean isBlocked) { mIsBlocked = isBlocked; mWasIsBlockedSet = true; + mCached = null; } private boolean isValid() { @@ -466,12 +725,30 @@ public class UnderlyingNetworkTracker { } private UnderlyingNetworkRecord build() { - return new UnderlyingNetworkRecord( - mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + if (!isValid()) { + throw new IllegalArgumentException( + "Called build before UnderlyingNetworkRecord was valid"); + } + + if (mCached == null) { + mCached = + new UnderlyingNetworkRecord( + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + } + + return mCached; } } } + private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback + implements ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + reevaluateNetworks(); + } + } + /** Callbacks for being notified of the changes in, or to the selected underlying network. */ public interface UnderlyingNetworkTrackerCallback { /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 528f240b99..ca7463884d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -88,13 +88,13 @@ public class TelephonySubscriptionTrackerTest { private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map> TEST_PRIVILEGED_PACKAGES = Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME)); - private static final Map TEST_SUBID_TO_GROUP_MAP; + private static final Map TEST_SUBID_TO_INFO_MAP; static { - final Map subIdToGroupMap = new HashMap<>(); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID); - TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); + final Map subIdToGroupMap = new HashMap<>(); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2); + TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap); } @NonNull private final Context mContext; @@ -190,13 +190,13 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map> privilegedPackages) { - return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, privilegedPackages); + return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( - Map subIdToGroupMap, + Map subIdToInfoMap, Map> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToGroupMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -371,7 +371,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +380,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 0b72cd93e8..a36fd797d1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -42,12 +42,14 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; -import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; @@ -98,11 +100,13 @@ public class UnderlyingNetworkTrackerTest { @Mock private Context mContext; @Mock private VcnNetworkProvider mVcnNetworkProvider; @Mock private ConnectivityManager mConnectivityManager; + @Mock private TelephonyManager mTelephonyManager; + @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; @Mock private Network mNetwork; - @Captor private ArgumentCaptor mRouteSelectionCallbackCaptor; + @Captor private ArgumentCaptor mUnderlyingNetworkListenerCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; @@ -127,6 +131,13 @@ public class UnderlyingNetworkTrackerTest { mConnectivityManager, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService( + mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mContext, + mCarrierConfigManager, + Context.CARRIER_CONFIG_SERVICE, + CarrierConfigManager.class); when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); @@ -163,26 +174,26 @@ public class UnderlyingNetworkTrackerTest { @Test public void testNetworkCallbacksRegisteredOnStartupForTestMode() { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); final VcnContext vcnContext = - spy( - new VcnContext( - mContext, - mTestLooper.getLooper(), - mVcnNetworkProvider, - true /* isInTestMode */)); + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */); - mUnderlyingNetworkTracker = - new UnderlyingNetworkTracker( - vcnContext, - SUB_GROUP, - mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), - mNetworkTrackerCb); + new UnderlyingNetworkTracker( + vcnContext, + SUB_GROUP, + mSubscriptionSnapshot, + Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), + mNetworkTrackerCb); - verify(mConnectivityManager) - .requestBackgroundNetwork( + verify(cm) + .registerNetworkCallback( eq(getTestNetworkRequest(INITIAL_SUB_IDS)), - any(RouteSelectionCallback.class), + any(UnderlyingNetworkListener.class), any()); } @@ -200,9 +211,19 @@ public class UnderlyingNetworkTrackerTest { } verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(expectedSubIds)), - any(RouteSelectionCallback.class), + any(UnderlyingNetworkListener.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiEntryRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiExitRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), any()); } @@ -218,9 +239,10 @@ public class UnderlyingNetworkTrackerTest { mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); // verify that initially-filed bringup requests are unregistered (cell + wifi) - verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1)) + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); } @@ -231,6 +253,24 @@ public class UnderlyingNetworkTrackerTest { .build(); } + private NetworkRequest getWifiEntryRssiThresholdRequest(Set netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) + .build(); + } + + private NetworkRequest getWifiExitRssiThresholdRequest(Set netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) + .build(); + } + private NetworkRequest getCellRequestForSubId(int subId) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) @@ -239,7 +279,11 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { - return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); + return getExpectedRequestBase() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .setSubscriptionIds(netCapsSubIds) + .build(); } private NetworkRequest getTestNetworkRequest(Set netCapsSubIds) { @@ -265,11 +309,12 @@ public class UnderlyingNetworkTrackerTest { public void testTeardown() { mUnderlyingNetworkTracker.teardown(); - // Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x - // for each subId) - verify(mConnectivityManager, times(3)) + // Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for + // each subId), and 1 for each of the Wifi signal strength thresholds + verify(mConnectivityManager, times(5)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); } @Test @@ -302,19 +347,19 @@ public class UnderlyingNetworkTrackerTest { verifyRegistrationOnAvailableAndGetCallback(); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() { + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback( + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), - mRouteSelectionCallbackCaptor.capture(), + mUnderlyingNetworkListenerCaptor.capture(), any()); - RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); + UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue(); cb.onAvailable(mNetwork); cb.onCapabilitiesChanged(mNetwork, networkCapabilities); cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); @@ -332,7 +377,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); @@ -347,7 +392,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); @@ -362,7 +407,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); @@ -381,7 +426,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkResumed() { - RouteSelectionCallback cb = + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -401,7 +446,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForBlocked() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); @@ -416,7 +461,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkLoss() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLost(mNetwork); @@ -425,7 +470,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackIgnoresDuplicateRecord() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -433,4 +478,6 @@ public class UnderlyingNetworkTrackerTest { // UnderlyingNetworkRecord does not actually change verifyNoMoreInteractions(mNetworkTrackerCb); } + + // TODO (b/187991063): Add tests for network prioritization } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 1ecb4c9ee2..c747bc096a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -54,6 +54,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; import com.android.internal.util.State; import com.android.internal.util.WakeupMessage; @@ -73,6 +74,12 @@ import java.util.concurrent.TimeUnit; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final SubscriptionInfo TEST_SUB_INFO = mock(SubscriptionInfo.class); + + static { + doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid(); + } + protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); protected static final InetAddress TEST_DNS_ADDR_2 = @@ -116,7 +123,7 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; From 259d8e759abc10f2faa3d010f1b55a62c3371552 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Fri, 14 May 2021 14:54:40 -0700 Subject: [PATCH 0222/1057] Update VCN Owners Post-Initial-Development Owners files update for VCN now that primary development is complete and the codebase is stable. Bug: 8675309 Test: compilation Change-Id: Ie686729b33f0a7e1c3414374ce4bf3d7ef514a22 --- Vcn/framework-b/src/android/net/vcn/OWNERS | 2 +- Vcn/service-b/src/com/android/server/vcn/OWNERS | 2 +- Vcn/tests/unit/OWNERS | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/OWNERS b/Vcn/framework-b/src/android/net/vcn/OWNERS index 33b9f0f75f..2441e77246 100644 --- a/Vcn/framework-b/src/android/net/vcn/OWNERS +++ b/Vcn/framework-b/src/android/net/vcn/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/OWNERS b/Vcn/service-b/src/com/android/server/vcn/OWNERS index 33b9f0f75f..2441e77246 100644 --- a/Vcn/service-b/src/com/android/server/vcn/OWNERS +++ b/Vcn/service-b/src/com/android/server/vcn/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com \ No newline at end of file diff --git a/Vcn/tests/unit/OWNERS b/Vcn/tests/unit/OWNERS index 33b9f0f75f..2441e77246 100644 --- a/Vcn/tests/unit/OWNERS +++ b/Vcn/tests/unit/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com \ No newline at end of file From 1ea47567e5d39f6ad33f11a31e344473f7a9da93 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 14 May 2021 14:53:40 -0700 Subject: [PATCH 0223/1057] Remove underlying network caps Bug: 182219992 Test: atest FrameworksVcnTests Change-Id: Ic2fec8a87fd19a1780333c61759c4092598d349e --- .../net/vcn/VcnGatewayConnectionConfig.java | 93 ------------------- .../server/vcn/UnderlyingNetworkTracker.java | 8 -- .../server/vcn/VcnGatewayConnection.java | 3 - .../vcn/VcnGatewayConnectionConfigTest.java | 12 +-- .../vcn/UnderlyingNetworkTrackerTest.java | 3 - .../vcn/VcnGatewayConnectionTestBase.java | 2 +- 6 files changed, 2 insertions(+), 119 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 2df3e6c7ec..d59ad6f888 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -161,9 +161,6 @@ public final class VcnGatewayConnectionConfig { private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; - private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; - @NonNull private final SortedSet mUnderlyingCapabilities; - private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -175,13 +172,11 @@ public final class VcnGatewayConnectionConfig { @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, - @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); - mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; @@ -198,16 +193,12 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); - final PersistableBundle underlyingCapsBundle = - in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( - underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -306,36 +297,6 @@ public final class VcnGatewayConnectionConfig { return Collections.unmodifiableSet(mExposedCapabilities); } - /** - * Returns all capabilities required of underlying networks. - * - *

      The returned integer-value capabilities will be sorted in ascending numerical order. - * - * @see Builder#addRequiredUnderlyingCapability(int) - * @see Builder#removeRequiredUnderlyingCapability(int) - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public int[] getRequiredUnderlyingCapabilities() { - // Sorted set guarantees ordering - return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities)); - } - - /** - * Returns all capabilities required of underlying networks. - * - *

      Left to prevent the need to make major changes while changes are actively in flight. - * - * @deprecated use getRequiredUnderlyingCapabilities() instead - * @hide - */ - @Deprecated - @NonNull - public Set getAllUnderlyingCapabilities() { - return Collections.unmodifiableSet(mUnderlyingCapabilities); - } - /** * Retrieves the configured retry intervals. * @@ -372,15 +333,10 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); - final PersistableBundle underlyingCapsBundle = - PersistableBundleUtils.fromList( - new ArrayList<>(mUnderlyingCapabilities), - PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); - result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -392,7 +348,6 @@ public final class VcnGatewayConnectionConfig { return Objects.hash( mGatewayConnectionName, mExposedCapabilities, - mUnderlyingCapabilities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); } @@ -406,7 +361,6 @@ public final class VcnGatewayConnectionConfig { final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mExposedCapabilities.equals(rhs.mExposedCapabilities) - && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; } @@ -418,7 +372,6 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); - @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; @@ -489,51 +442,6 @@ public final class VcnGatewayConnectionConfig { return this; } - /** - * Require a capability for Networks underlying this VCN Gateway Connection. - * - * @param underlyingCapability the capability that a network MUST have in order to be an - * underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public Builder addRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.add(underlyingCapability); - return this; - } - - /** - * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection. - * - *

      Calling this method will allow Networks that do NOT have this capability to be - * selected as an underlying network for this VCN Gateway Connection. However, underlying - * networks MAY still have the removed capability. - * - * @param underlyingCapability the capability that a network DOES NOT need to have in order - * to be an underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap - public Builder removeRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.remove(underlyingCapability); - return this; - } - /** * Set the retry interval between VCN establishment attempts upon successive failures. * @@ -598,7 +506,6 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, - mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index fb4c6236a9..b05662e167 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -108,7 +108,6 @@ public class UnderlyingNetworkTracker { @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; - @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @@ -133,13 +132,11 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb) { this( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, cb, new Dependencies()); } @@ -148,16 +145,11 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); - mRequiredUnderlyingNetworkCapabilities = - Objects.requireNonNull( - requiredUnderlyingNetworkCapabilities, - "Missing requiredUnderlyingNetworkCapabilities"); mCb = Objects.requireNonNull(cb, "Missing cb"); mDeps = Objects.requireNonNull(deps, "Missing deps"); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 5cecff6f93..dff04bfc6d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -673,7 +673,6 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext, subscriptionGroup, mLastSnapshot, - mConnectionConfig.getAllUnderlyingCapabilities(), mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); @@ -2274,13 +2273,11 @@ public class VcnGatewayConnection extends StateMachine { VcnContext vcnContext, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - Set requiredUnderlyingNetworkCapabilities, UnderlyingNetworkTrackerCallback callback) { return new UnderlyingNetworkTracker( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, callback); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index c59dcf879b..4ce78aa4d8 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -92,10 +92,6 @@ public class VcnGatewayConnectionConfigTest { builder.addExposedCapability(caps); } - for (int caps : UNDERLYING_CAPS) { - builder.addRequiredUnderlyingCapability(caps); - } - return builder.build(); } @@ -141,9 +137,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyExposedCaps() { try { - newBuilder() - .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); + newBuilder().build(); fail("Expected exception due to invalid exposed capabilities"); } catch (IllegalArgumentException e) { @@ -187,10 +181,6 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); - int[] underlyingCaps = config.getRequiredUnderlyingCapabilities(); - Arrays.sort(underlyingCaps); - assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); - assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index a36fd797d1..f91575b670 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -61,7 +61,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; -import java.util.Collections; import java.util.Set; import java.util.UUID; @@ -146,7 +145,6 @@ public class UnderlyingNetworkTrackerTest { mVcnContext, SUB_GROUP, mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); } @@ -187,7 +185,6 @@ public class UnderlyingNetworkTrackerTest { vcnContext, SUB_GROUP, mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); verify(cm) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index c747bc096a..860a919aa9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -173,7 +173,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any(), any(), any()); + .newUnderlyingNetworkTracker(any(), any(), any(), any()); doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); From 11a498bebb71085f6ef6ec0b533c4047a2d050d2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 14 May 2021 15:01:16 -0700 Subject: [PATCH 0224/1057] Make VcnTransportInfo unparcel to null if no data contained When VcnTransportInfo is redacted, it contains no useful information. In order to preserve the abstraction, the VcnTransportInfo should be unparcelled to null Bug: 8675309 Test: atest VcnTransportInfoTest Change-Id: Ia9dbb9f259027acc74004eb1207e0a13cea56088 --- .../src/android/net/vcn/VcnTransportInfo.java | 24 +++++++++++-- .../android/net/vcn/VcnTransportInfoTest.java | 36 +++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 1f1818420b..25a257423c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -16,11 +16,12 @@ package android.net.vcn; -import static android.net.NetworkCapabilities.REDACT_NONE; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; import android.os.Parcel; @@ -108,13 +109,24 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @Override @NonNull public TransportInfo makeCopy(long redactions) { + if ((redactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) != 0) { + return new VcnTransportInfo(null, INVALID_SUBSCRIPTION_ID); + } + return new VcnTransportInfo( (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId); } @Override public long getApplicableRedactions() { - return (mWifiInfo == null) ? REDACT_NONE : mWifiInfo.getApplicableRedactions(); + long redactions = REDACT_FOR_NETWORK_SETTINGS; + + // Add additional wifi redactions if necessary + if (mWifiInfo != null) { + redactions |= mWifiInfo.getApplicableRedactions(); + } + + return redactions; } /** {@inheritDoc} */ @@ -135,6 +147,14 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); final WifiInfo wifiInfo = in.readParcelable(null); + + // If all fields are their null values, return null TransportInfo to avoid + // leaking information about this being a VCN Network (instead of macro + // cellular, etc) + if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { + return null; + } + return new VcnTransportInfo(wifiInfo, subId); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 00a0bffa15..19df3c7526 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -17,7 +17,6 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; -import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -26,12 +25,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import android.net.NetworkCapabilities; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.Parcel; import org.junit.Test; +import java.util.Arrays; + public class VcnTransportInfoTest { private static final int SUB_ID = 1; private static final int NETWORK_ID = 5; @@ -55,6 +57,19 @@ public class VcnTransportInfoTest { assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId()); } + @Test + public void testMakeCopyRedactForNetworkSettings() { + for (VcnTransportInfo info : Arrays.asList(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO)) { + assertEquals( + INVALID_SUBSCRIPTION_ID, + ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getSubId()); + assertNull( + ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getWifiInfo()); + } + } + @Test public void testMakeCopyRedactForAccessFineLocation() { assertEquals( @@ -75,11 +90,20 @@ public class VcnTransportInfoTest { } @Test - public void testApplicableRedactions() { - assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions()); - assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS - | REDACT_FOR_NETWORK_SETTINGS, - WIFI_UNDERLYING_INFO.getApplicableRedactions()); + public void testParcelUnparcel() { + verifyParcelingIsNull(CELL_UNDERLYING_INFO); + verifyParcelingIsNull(WIFI_UNDERLYING_INFO); + } + + private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { + VcnTransportInfo redacted = (VcnTransportInfo) vcnTransportInfo.makeCopy( + NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS); + + Parcel parcel = Parcel.obtain(); + redacted.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + + assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); } @Test From ed0e354d8e895f0871d2e1e0f86b8282031b407e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 20 May 2021 16:42:42 -0700 Subject: [PATCH 0225/1057] Prevent concurrent modification exceptions in VcnManagementService In order to prevent concurrent modifications from triggering an exception in the dump, proxy it to the handler thread. Adding locks was considered, but would require auditing all callbacks and proxying them to the handler threads in order to ensure lock inversion and deadlocks never occur. Bug: 188840899 Test: FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: Ibcc4bdc06301dd77260adaa0c086529f8f524679 --- .../android/server/VcnManagementService.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e7e3ce9d2d..9bf6a5d0d1 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -148,6 +148,7 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); public static final boolean VDBG = false; // STOPSHIP: if true @@ -999,46 +1000,50 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - pw.println("VcnManagementService dump:"); - pw.increaseIndent(); - - pw.println("mNetworkProvider:"); - pw.increaseIndent(); - mNetworkProvider.dump(pw); - pw.decreaseIndent(); - pw.println(); - - pw.println("mTrackingNetworkCallback:"); - pw.increaseIndent(); - mTrackingNetworkCallback.dump(pw); - pw.decreaseIndent(); - pw.println(); - - synchronized (mLock) { - pw.println("mLastSnapshot:"); + // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. + mHandler.runWithScissors(() -> { + pw.println("VcnManagementService dump:"); pw.increaseIndent(); - mLastSnapshot.dump(pw); + + pw.println("mNetworkProvider:"); + pw.increaseIndent(); + mNetworkProvider.dump(pw); pw.decreaseIndent(); pw.println(); - pw.println("mConfigs:"); + pw.println("mTrackingNetworkCallback:"); pw.increaseIndent(); - for (Entry entry : mConfigs.entrySet()) { - pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName()); + mTrackingNetworkCallback.dump(pw); + pw.decreaseIndent(); + pw.println(); + + synchronized (mLock) { + pw.println("mLastSnapshot:"); + pw.increaseIndent(); + mLastSnapshot.dump(pw); + pw.decreaseIndent(); + pw.println(); + + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println(entry.getKey() + ": " + + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); + + pw.println("mVcns:"); + pw.increaseIndent(); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.decreaseIndent(); + pw.println(); } - pw.decreaseIndent(); - pw.println(); - pw.println("mVcns:"); - pw.increaseIndent(); - for (Vcn vcn : mVcns.values()) { - vcn.dump(pw); - } pw.decreaseIndent(); - pw.println(); - } - - pw.decreaseIndent(); + }, DUMP_TIMEOUT_MILLIS); } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService From ccd8c92926190f12cf8ba3bf76f9ab3d8f71cc49 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 21 May 2021 17:13:14 -0700 Subject: [PATCH 0226/1057] Copy up/downstream bandwidth and TCP buffer sizes from underlying This change copies the relevant pieces of information used to tune the system for performance Bug: 188943592 Test: atest FrameworksVcnTests Change-Id: I2d5dc5b9000fa9d0da9d34772b3704110694c526 --- .../server/vcn/VcnGatewayConnection.java | 21 ++++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 12 ++++++++--- .../server/vcn/VcnGatewayConnectionTest.java | 7 +++++++ .../vcn/VcnGatewayConnectionTestBase.java | 4 ++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 5cecff6f93..840157b7e3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1970,6 +1970,9 @@ public class VcnGatewayConnection extends StateMachine { } builder.setAdministratorUids(adminUids); + builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps()); + builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps()); + // Set TransportInfo for SysUI use (never parcelled out of SystemServer). if (underlyingCaps.hasTransport(TRANSPORT_WIFI) && underlyingCaps.getTransportInfo() instanceof WifiInfo) { @@ -1986,6 +1989,11 @@ public class VcnGatewayConnection extends StateMachine { "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + " non-null underlying network"); } + } else { + Slog.wtf( + TAG, + "No underlying network while building network capabilities", + new IllegalStateException()); } return builder.build(); @@ -2013,7 +2021,18 @@ public class VcnGatewayConnection extends StateMachine { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, null /*iface*/, RouteInfo.RTN_UNICAST)); - final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu(); + int underlyingMtu = 0; + if (underlying != null) { + final LinkProperties underlyingLp = underlying.linkProperties; + + lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); + underlyingMtu = underlyingLp.getMtu(); + } else { + Slog.wtf( + TAG, + "No underlying network while building link properties", + new IllegalStateException()); + } lp.setMtu( MtuUtils.getMtu( ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 39f7386cbb..9c93f81114 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -200,6 +200,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection public void testMigration() throws Exception { triggerChildOpened(); + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); @@ -207,7 +210,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mIpSecSvc, times(2)) .setNetworkForTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), - eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), + eq(TEST_UNDERLYING_NETWORK_RECORD_2.network), any()); for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { @@ -226,8 +229,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection MtuUtils.getMtu( saProposals, mConfig.getMaxMtu(), - TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu()); - verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu())); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu()); + verify(mNetworkAgent).sendLinkProperties( + argThat(lp -> expectedMtu == lp.getMtu() + && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); } private void triggerChildOpened() { @@ -297,6 +302,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection final LinkProperties lp = lpCaptor.getValue(); assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses()); assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes()); final NetworkCapabilities nc = ncCaptor.getValue(); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 9705f0fc6b..a4f95e03e9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -74,6 +74,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map TEST_SUBID_TO_GROUP_MAP; + private static final int TEST_UPSTREAM_BANDWIDTH = 1234; + private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; + static { final Map subIdToGroupMap = new HashMap<>(); subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); @@ -106,6 +109,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setNetworkSpecifier( new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); } + capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH); + capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -130,6 +135,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); + assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps()); + assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps()); final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo(); if (transportType == TRANSPORT_WIFI) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index c747bc096a..0a4fcbcb28 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -99,6 +99,7 @@ public class VcnGatewayConnectionTestBase { protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -108,8 +109,10 @@ public class VcnGatewayConnectionTestBase { static { TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500); + TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1); } + protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -119,6 +122,7 @@ public class VcnGatewayConnectionTestBase { static { TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2); } protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = From cef193006e46f36c8887249a900f96a667bc1021 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 20 May 2021 17:12:47 -0700 Subject: [PATCH 0227/1057] Add additional dump information for UnderlyingNetworkTracker This change adds additional dump information to facilitate the resolution of bug reports. Additionally, this method cleans up dump formatting. Bug: 188842647 Test: atest FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: I5ce7fe05eb21a89c2034079223ef44f05db2a087 --- .../android/server/VcnManagementService.java | 16 +--- .../server/vcn/UnderlyingNetworkTracker.java | 73 ++++++++++++++++--- .../src/com/android/server/vcn/Vcn.java | 3 + .../server/vcn/VcnGatewayConnection.java | 10 +-- 4 files changed, 69 insertions(+), 33 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 9bf6a5d0d1..57adcb6e39 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -998,30 +998,18 @@ public class VcnManagementService extends IVcnManagementService.Stub { protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| "); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. mHandler.runWithScissors(() -> { - pw.println("VcnManagementService dump:"); - pw.increaseIndent(); - - pw.println("mNetworkProvider:"); - pw.increaseIndent(); mNetworkProvider.dump(pw); - pw.decreaseIndent(); pw.println(); - pw.println("mTrackingNetworkCallback:"); - pw.increaseIndent(); mTrackingNetworkCallback.dump(pw); - pw.decreaseIndent(); pw.println(); synchronized (mLock) { - pw.println("mLastSnapshot:"); - pw.increaseIndent(); mLastSnapshot.dump(pw); - pw.decreaseIndent(); pw.println(); pw.println("mConfigs:"); @@ -1041,8 +1029,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.decreaseIndent(); pw.println(); } - - pw.decreaseIndent(); }, DUMP_TIMEOUT_MILLIS); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index fb4c6236a9..5414a5206a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -40,6 +40,7 @@ import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -106,6 +107,17 @@ public class UnderlyingNetworkTracker { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int PRIORITY_ANY = Integer.MAX_VALUE; + private static final SparseArray PRIORITY_TO_STRING_MAP = new SparseArray<>(); + + static { + PRIORITY_TO_STRING_MAP.put( + PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY"); + } + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; @@ -403,12 +415,12 @@ public class UnderlyingNetworkTracker { } private void reevaluateNetworks() { - TreeSet sorted = - new TreeSet<>( - UnderlyingNetworkRecord.getComparator( - mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig)); - sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks()); + if (mRouteSelectionCallback == null) { + return; // UnderlyingNetworkTracker has quit. + } + TreeSet sorted = + mRouteSelectionCallback.getSortedUnderlyingNetworks(); UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); if (Objects.equals(mCurrentRecord, candidate)) { return; @@ -454,17 +466,23 @@ public class UnderlyingNetworkTracker { private final Map mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); - private List getUnderlyingNetworks() { - final List records = new ArrayList<>(); + private TreeSet getSortedUnderlyingNetworks() { + TreeSet sorted = + new TreeSet<>( + UnderlyingNetworkRecord.getComparator( + mSubscriptionGroup, + mLastSnapshot, + mCurrentRecord, + mCarrierConfig)); for (UnderlyingNetworkRecord.Builder builder : mUnderlyingNetworkRecordBuilders.values()) { if (builder.isValid()) { - records.add(builder.build()); + sorted.add(builder.build()); } } - return records; + return sorted; } @Override @@ -668,10 +686,21 @@ public class UnderlyingNetworkTracker { } /** Dumps the state of this record for logging and debugging purposes. */ - public void dump(IndentingPrintWriter pw) { + private void dump( + IndentingPrintWriter pw, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); + final int priorityClass = + calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig); + pw.println( + "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " (" + + priorityClass + ")"); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); @@ -741,6 +770,30 @@ public class UnderlyingNetworkTracker { } } + /** Dumps the state of this record for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkTracker:"); + pw.increaseIndent(); + + pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig)); + pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig)); + pw.println( + "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network)); + + pw.println("Underlying networks:"); + pw.increaseIndent(); + if (mRouteSelectionCallback != null) { + for (UnderlyingNetworkRecord record : + mRouteSelectionCallback.getSortedUnderlyingNetworks()) { + record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig); + } + } + pw.decreaseIndent(); + pw.println(); + + pw.decreaseIndent(); + } + private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback implements ActiveDataSubscriptionIdListener { @Override diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f918827e96..6b4ee693c9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -557,11 +557,14 @@ public class Vcn extends Handler { pw.println("mCurrentStatus: " + mCurrentStatus); pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled); + pw.println(); pw.println("mVcnGatewayConnections:"); + pw.increaseIndent(); for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { gw.dump(pw); } + pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 840157b7e3..fbbae97353 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2188,15 +2188,9 @@ public class VcnGatewayConnection extends StateMachine { pw.println( "mNetworkAgent.getNetwork(): " + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + pw.println(); - pw.println("mUnderlying:"); - pw.increaseIndent(); - if (mUnderlying != null) { - mUnderlying.dump(pw); - } else { - pw.println("null"); - } - pw.decreaseIndent(); + mUnderlyingNetworkTracker.dump(pw); pw.println(); pw.decreaseIndent(); From 0ad869e6d6b8e14a058bd5ffd97ec03e16cfb9e2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 May 2021 13:43:47 -0700 Subject: [PATCH 0228/1057] Add local log This change adds a local log buffer to the VcnManagementService, ensuring that if the system-wide log buffer saturates, some basic VCN logs are retained Bug: 188842647 Test: atest FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: Ib250e38fc5a034a6d2a327b2ee159e7186a15ada --- .../android/server/VcnManagementService.java | 74 +++++++++++++++---- .../vcn/TelephonySubscriptionTracker.java | 3 - .../server/vcn/UnderlyingNetworkTracker.java | 22 ++++-- .../src/com/android/server/vcn/Vcn.java | 10 ++- .../server/vcn/VcnGatewayConnection.java | 12 ++- .../server/vcn/VcnNetworkProvider.java | 4 + 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 57adcb6e39..7e2274b65f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -64,6 +64,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.LocalLog; import android.util.Log; import android.util.Slog; @@ -149,6 +150,10 @@ import java.util.concurrent.TimeUnit; public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); + private static final int LOCAL_LOG_LINE_COUNT = 128; + + // Public for use in all other VCN classes + @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT); public static final boolean VDBG = false; // STOPSHIP: if true @@ -242,13 +247,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { try { configBundle = mConfigDiskRwHelper.readFromDisk(); } catch (IOException e1) { - Slog.e(TAG, "Failed to read configs from disk; retrying", e1); + logErr("Failed to read configs from disk; retrying", e1); // Retry immediately. The IOException may have been transient. try { configBundle = mConfigDiskRwHelper.readFromDisk(); } catch (IOException e2) { - Slog.wtf(TAG, "Failed to read configs from disk", e2); + logWtf("Failed to read configs from disk", e2); return; } } @@ -440,7 +445,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; - Slog.d(TAG, "new snapshot: " + mLastSnapshot); + logDbg("new snapshot: " + mLastSnapshot); // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { @@ -543,7 +548,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + logDbg("Starting VCN config for subGrp: " + subscriptionGroup); // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. @@ -568,7 +573,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startOrUpdateVcnLocked( @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); + logDbg("Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); @@ -594,7 +599,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!config.getProvisioningPackageName().equals(opPkgName)) { throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); } - Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup); + logDbg("VCN config updated for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); @@ -620,7 +625,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(opPkgName, "opPkgName was null"); - Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); + logDbg("VCN config cleared for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); @@ -683,7 +688,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { VcnConfig::toPersistableBundle); mConfigDiskRwHelper.writeToDisk(bundle); } catch (IOException e) { - Slog.e(TAG, "Failed to save configs to disk", e); + logErr("Failed to save configs to disk", e); throw new ServiceSpecificException(0, "Failed to save configs"); } } @@ -793,7 +798,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { for (int subId : networkCapabilities.getSubscriptionIds()) { // Verify that all subscriptions point to the same group if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { - Slog.wtf(TAG, "Got multiple subscription groups for a single network"); + logWtf("Got multiple subscription groups for a single network"); } subGrp = snapshot.getGroupForSubId(subId); @@ -859,10 +864,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result); - if (VDBG) { - Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + "; and lp: " + linkProperties + "; result = " + policy); - } return policy; }); } @@ -954,14 +957,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) { resultStatus = vcnStatus; } else { - Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus); + logWtf("Unknown VCN status: " + vcnStatus); resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } try { cbInfo.mCallback.onVcnStatusChanged(resultStatus); } catch (RemoteException e) { - Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); + logDbg("VcnStatusCallback threw on VCN status change", e); } } } finally { @@ -989,6 +992,43 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, msg); + LOCAL_LOG.log(TAG + " VDBG: " + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, msg); + LOCAL_LOG.log(TAG + " DBG: " + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, msg, tr); + LOCAL_LOG.log(TAG + " DBG: " + msg + tr); + } + + private void logErr(String msg) { + Slog.e(TAG, msg); + LOCAL_LOG.log(TAG + " ERR: " + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, msg, tr); + LOCAL_LOG.log(TAG + " ERR: " + msg + tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, msg); + LOCAL_LOG.log(TAG + " WTF: " + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, msg, tr); + LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + } + /** * Dumps the state of the VcnManagementService for logging and debugging purposes. * @@ -1029,6 +1069,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.decreaseIndent(); pw.println(); } + + pw.println("Local log:"); + pw.increaseIndent(); + LOCAL_LOG.dump(pw); + pw.decreaseIndent(); + pw.println(); }, DUMP_TIMEOUT_MILLIS); } diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 5565ccb6cf..fca706b707 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -39,7 +39,6 @@ import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -222,12 +221,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { if (SubscriptionManager.isValidSubscriptionId(subId)) { final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) { - Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId)); mReadySubIdsBySlotId.put(slotId, subId); handleSubscriptionsChanged(); } } else { - Slog.v(TAG, "Slot unloaded: " + slotId); mReadySubIdsBySlotId.remove(slotId); handleSubscriptionsChanged(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 5414a5206a..7320359514 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -20,6 +20,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import static com.android.server.VcnManagementService.LOCAL_LOG; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; @@ -433,7 +435,7 @@ public class UnderlyingNetworkTracker { private static boolean isOpportunistic( @NonNull TelephonySubscriptionSnapshot snapshot, Set subIds) { if (snapshot == null) { - Slog.wtf(TAG, "Got null snapshot"); + logWtf("Got null snapshot"); return false; } @@ -504,7 +506,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got capabilities change for unknown key: " + network); + logWtf("Got capabilities change for unknown key: " + network); return; } @@ -520,7 +522,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got link properties change for unknown key: " + network); + logWtf("Got link properties change for unknown key: " + network); return; } @@ -535,7 +537,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got blocked status change for unknown key: " + network); + logWtf("Got blocked status change for unknown key: " + network); return; } @@ -623,7 +625,7 @@ public class UnderlyingNetworkTracker { // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED if (isBlocked) { - Slog.wtf(TAG, "Network blocked for System Server: " + network); + logWtf("Network blocked for System Server: " + network); return PRIORITY_ANY; } @@ -770,6 +772,16 @@ public class UnderlyingNetworkTracker { } } + private static void logWtf(String msg) { + Slog.wtf(TAG, msg); + LOCAL_LOG.log(TAG + " WTF: " + msg); + } + + private static void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, msg, tr); + LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + } + /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkTracker:"); diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 6b4ee693c9..f7d61367c8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -513,37 +514,44 @@ public class Vcn extends Handler { } private String getLogPrefix() { - return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: "; + return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] "; } private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index fbbae97353..55e3ed6201 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -30,6 +30,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; +import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -1645,7 +1646,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform transform, int direction) { if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) { - Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction); + logWtf("Applying transform for unexpected direction: " + direction); } try { @@ -2134,37 +2135,44 @@ public class VcnGatewayConnection extends StateMachine { + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + mConnectionConfig.getGatewayConnectionName() - + "]: "; + + "] "; } private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 72cd788032..31ee2477fa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -172,6 +172,10 @@ public class VcnNetworkProvider extends NetworkProvider { } private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + if (VDBG) { + Slog.v(TAG, "Network request withdrawn: Request = " + request); + } + mRequests.remove(request); } From 8ba7e3e72972463dea01db1ee5297a524557c636 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 20 May 2021 16:42:42 -0700 Subject: [PATCH 0229/1057] Prevent concurrent modification exceptions in VcnManagementService In order to prevent concurrent modifications from triggering an exception in the dump, proxy it to the handler thread. Adding locks was considered, but would require auditing all callbacks and proxying them to the handler threads in order to ensure lock inversion and deadlocks never occur. Bug: 188840899 Test: FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: Ibcc4bdc06301dd77260adaa0c086529f8f524679 Merged-In: Ibcc4bdc06301dd77260adaa0c086529f8f524679 (cherry picked from commit ed0e354d8e895f0871d2e1e0f86b8282031b407e) --- .../android/server/VcnManagementService.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index bcbd692a2f..be9221c436 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -148,6 +148,7 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); public static final boolean VDBG = false; // STOPSHIP: if true @@ -1001,46 +1002,50 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - pw.println("VcnManagementService dump:"); - pw.increaseIndent(); - - pw.println("mNetworkProvider:"); - pw.increaseIndent(); - mNetworkProvider.dump(pw); - pw.decreaseIndent(); - pw.println(); - - pw.println("mTrackingNetworkCallback:"); - pw.increaseIndent(); - mTrackingNetworkCallback.dump(pw); - pw.decreaseIndent(); - pw.println(); - - synchronized (mLock) { - pw.println("mLastSnapshot:"); + // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. + mHandler.runWithScissors(() -> { + pw.println("VcnManagementService dump:"); pw.increaseIndent(); - mLastSnapshot.dump(pw); + + pw.println("mNetworkProvider:"); + pw.increaseIndent(); + mNetworkProvider.dump(pw); pw.decreaseIndent(); pw.println(); - pw.println("mConfigs:"); + pw.println("mTrackingNetworkCallback:"); pw.increaseIndent(); - for (Entry entry : mConfigs.entrySet()) { - pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName()); + mTrackingNetworkCallback.dump(pw); + pw.decreaseIndent(); + pw.println(); + + synchronized (mLock) { + pw.println("mLastSnapshot:"); + pw.increaseIndent(); + mLastSnapshot.dump(pw); + pw.decreaseIndent(); + pw.println(); + + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println(entry.getKey() + ": " + + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); + + pw.println("mVcns:"); + pw.increaseIndent(); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.decreaseIndent(); + pw.println(); } - pw.decreaseIndent(); - pw.println(); - pw.println("mVcns:"); - pw.increaseIndent(); - for (Vcn vcn : mVcns.values()) { - vcn.dump(pw); - } pw.decreaseIndent(); - pw.println(); - } - - pw.decreaseIndent(); + }, DUMP_TIMEOUT_MILLIS); } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService From d3ba5899b632829a0ee25c4f5c4c7aadb9be725b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 21 May 2021 17:13:14 -0700 Subject: [PATCH 0230/1057] Copy up/downstream bandwidth and TCP buffer sizes from underlying This change copies the relevant pieces of information used to tune the system for performance Bug: 188943592 Test: atest FrameworksVcnTests Change-Id: I2d5dc5b9000fa9d0da9d34772b3704110694c526 Merged-In: I2d5dc5b9000fa9d0da9d34772b3704110694c526 (cherry picked from commit ccd8c92926190f12cf8ba3bf76f9ab3d8f71cc49) --- .../server/vcn/VcnGatewayConnection.java | 21 ++++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 12 ++++++++--- .../server/vcn/VcnGatewayConnectionTest.java | 7 +++++++ .../vcn/VcnGatewayConnectionTestBase.java | 4 ++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index dff04bfc6d..345e7d9143 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1969,6 +1969,9 @@ public class VcnGatewayConnection extends StateMachine { } builder.setAdministratorUids(adminUids); + builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps()); + builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps()); + // Set TransportInfo for SysUI use (never parcelled out of SystemServer). if (underlyingCaps.hasTransport(TRANSPORT_WIFI) && underlyingCaps.getTransportInfo() instanceof WifiInfo) { @@ -1985,6 +1988,11 @@ public class VcnGatewayConnection extends StateMachine { "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + " non-null underlying network"); } + } else { + Slog.wtf( + TAG, + "No underlying network while building network capabilities", + new IllegalStateException()); } return builder.build(); @@ -2012,7 +2020,18 @@ public class VcnGatewayConnection extends StateMachine { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, null /*iface*/, RouteInfo.RTN_UNICAST)); - final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu(); + int underlyingMtu = 0; + if (underlying != null) { + final LinkProperties underlyingLp = underlying.linkProperties; + + lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); + underlyingMtu = underlyingLp.getMtu(); + } else { + Slog.wtf( + TAG, + "No underlying network while building link properties", + new IllegalStateException()); + } lp.setMtu( MtuUtils.getMtu( ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 39f7386cbb..9c93f81114 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -200,6 +200,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection public void testMigration() throws Exception { triggerChildOpened(); + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); @@ -207,7 +210,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mIpSecSvc, times(2)) .setNetworkForTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), - eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), + eq(TEST_UNDERLYING_NETWORK_RECORD_2.network), any()); for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { @@ -226,8 +229,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection MtuUtils.getMtu( saProposals, mConfig.getMaxMtu(), - TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu()); - verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu())); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu()); + verify(mNetworkAgent).sendLinkProperties( + argThat(lp -> expectedMtu == lp.getMtu() + && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); } private void triggerChildOpened() { @@ -297,6 +302,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection final LinkProperties lp = lpCaptor.getValue(); assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses()); assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes()); final NetworkCapabilities nc = ncCaptor.getValue(); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 9705f0fc6b..a4f95e03e9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -74,6 +74,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map TEST_SUBID_TO_GROUP_MAP; + private static final int TEST_UPSTREAM_BANDWIDTH = 1234; + private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; + static { final Map subIdToGroupMap = new HashMap<>(); subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); @@ -106,6 +109,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setNetworkSpecifier( new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); } + capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH); + capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -130,6 +135,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); + assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps()); + assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps()); final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo(); if (transportType == TRANSPORT_WIFI) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 860a919aa9..b97023a95d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -99,6 +99,7 @@ public class VcnGatewayConnectionTestBase { protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -108,8 +109,10 @@ public class VcnGatewayConnectionTestBase { static { TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500); + TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1); } + protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = new UnderlyingNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), @@ -119,6 +122,7 @@ public class VcnGatewayConnectionTestBase { static { TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2); } protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = From a655d7c86ed735eca4aa6b7287c58050500e2c8c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 20 May 2021 17:12:47 -0700 Subject: [PATCH 0231/1057] Add additional dump information for UnderlyingNetworkTracker This change adds additional dump information to facilitate the resolution of bug reports. Additionally, this method cleans up dump formatting. Bug: 188842647 Test: atest FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: I5ce7fe05eb21a89c2034079223ef44f05db2a087 Merged-In: I5ce7fe05eb21a89c2034079223ef44f05db2a087 (cherry picked from commit cef193006e46f36c8887249a900f96a667bc1021) --- .../android/server/VcnManagementService.java | 16 +--- .../server/vcn/UnderlyingNetworkTracker.java | 73 ++++++++++++++++--- .../src/com/android/server/vcn/Vcn.java | 3 + .../server/vcn/VcnGatewayConnection.java | 10 +-- 4 files changed, 69 insertions(+), 33 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index be9221c436..54388f25a8 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -1000,30 +1000,18 @@ public class VcnManagementService extends IVcnManagementService.Stub { protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| "); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. mHandler.runWithScissors(() -> { - pw.println("VcnManagementService dump:"); - pw.increaseIndent(); - - pw.println("mNetworkProvider:"); - pw.increaseIndent(); mNetworkProvider.dump(pw); - pw.decreaseIndent(); pw.println(); - pw.println("mTrackingNetworkCallback:"); - pw.increaseIndent(); mTrackingNetworkCallback.dump(pw); - pw.decreaseIndent(); pw.println(); synchronized (mLock) { - pw.println("mLastSnapshot:"); - pw.increaseIndent(); mLastSnapshot.dump(pw); - pw.decreaseIndent(); pw.println(); pw.println("mConfigs:"); @@ -1043,8 +1031,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.decreaseIndent(); pw.println(); } - - pw.decreaseIndent(); }, DUMP_TIMEOUT_MILLIS); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index b05662e167..92a4eededd 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -40,6 +40,7 @@ import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -106,6 +107,17 @@ public class UnderlyingNetworkTracker { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int PRIORITY_ANY = Integer.MAX_VALUE; + private static final SparseArray PRIORITY_TO_STRING_MAP = new SparseArray<>(); + + static { + PRIORITY_TO_STRING_MAP.put( + PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY"); + } + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @@ -395,12 +407,12 @@ public class UnderlyingNetworkTracker { } private void reevaluateNetworks() { - TreeSet sorted = - new TreeSet<>( - UnderlyingNetworkRecord.getComparator( - mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig)); - sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks()); + if (mRouteSelectionCallback == null) { + return; // UnderlyingNetworkTracker has quit. + } + TreeSet sorted = + mRouteSelectionCallback.getSortedUnderlyingNetworks(); UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); if (Objects.equals(mCurrentRecord, candidate)) { return; @@ -446,17 +458,23 @@ public class UnderlyingNetworkTracker { private final Map mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); - private List getUnderlyingNetworks() { - final List records = new ArrayList<>(); + private TreeSet getSortedUnderlyingNetworks() { + TreeSet sorted = + new TreeSet<>( + UnderlyingNetworkRecord.getComparator( + mSubscriptionGroup, + mLastSnapshot, + mCurrentRecord, + mCarrierConfig)); for (UnderlyingNetworkRecord.Builder builder : mUnderlyingNetworkRecordBuilders.values()) { if (builder.isValid()) { - records.add(builder.build()); + sorted.add(builder.build()); } } - return records; + return sorted; } @Override @@ -660,10 +678,21 @@ public class UnderlyingNetworkTracker { } /** Dumps the state of this record for logging and debugging purposes. */ - public void dump(IndentingPrintWriter pw) { + private void dump( + IndentingPrintWriter pw, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); + final int priorityClass = + calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig); + pw.println( + "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " (" + + priorityClass + ")"); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); @@ -733,6 +762,30 @@ public class UnderlyingNetworkTracker { } } + /** Dumps the state of this record for logging and debugging purposes. */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkTracker:"); + pw.increaseIndent(); + + pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig)); + pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig)); + pw.println( + "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network)); + + pw.println("Underlying networks:"); + pw.increaseIndent(); + if (mRouteSelectionCallback != null) { + for (UnderlyingNetworkRecord record : + mRouteSelectionCallback.getSortedUnderlyingNetworks()) { + record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig); + } + } + pw.decreaseIndent(); + pw.println(); + + pw.decreaseIndent(); + } + private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback implements ActiveDataSubscriptionIdListener { @Override diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f918827e96..6b4ee693c9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -557,11 +557,14 @@ public class Vcn extends Handler { pw.println("mCurrentStatus: " + mCurrentStatus); pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled); + pw.println(); pw.println("mVcnGatewayConnections:"); + pw.increaseIndent(); for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { gw.dump(pw); } + pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 345e7d9143..54a1da0752 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2187,15 +2187,9 @@ public class VcnGatewayConnection extends StateMachine { pw.println( "mNetworkAgent.getNetwork(): " + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + pw.println(); - pw.println("mUnderlying:"); - pw.increaseIndent(); - if (mUnderlying != null) { - mUnderlying.dump(pw); - } else { - pw.println("null"); - } - pw.decreaseIndent(); + mUnderlyingNetworkTracker.dump(pw); pw.println(); pw.decreaseIndent(); From c759bf57ccad65c197788cfa87519ca3a927a7a8 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 May 2021 13:43:47 -0700 Subject: [PATCH 0232/1057] Add local log This change adds a local log buffer to the VcnManagementService, ensuring that if the system-wide log buffer saturates, some basic VCN logs are retained Bug: 188842647 Test: atest FrameworksVcnTests Test: adb shell dumpsys vcn_management Change-Id: Ib250e38fc5a034a6d2a327b2ee159e7186a15ada Merged-In: Ib250e38fc5a034a6d2a327b2ee159e7186a15ada (cherry picked from commit 0ad869e6d6b8e14a058bd5ffd97ec03e16cfb9e2) --- .../android/server/VcnManagementService.java | 74 +++++++++++++++---- .../vcn/TelephonySubscriptionTracker.java | 3 - .../server/vcn/UnderlyingNetworkTracker.java | 22 ++++-- .../src/com/android/server/vcn/Vcn.java | 10 ++- .../server/vcn/VcnGatewayConnection.java | 12 ++- .../server/vcn/VcnNetworkProvider.java | 4 + 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 54388f25a8..7fb164a339 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -64,6 +64,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.LocalLog; import android.util.Log; import android.util.Slog; @@ -149,6 +150,10 @@ import java.util.concurrent.TimeUnit; public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); + private static final int LOCAL_LOG_LINE_COUNT = 128; + + // Public for use in all other VCN classes + @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT); public static final boolean VDBG = false; // STOPSHIP: if true @@ -242,13 +247,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { try { configBundle = mConfigDiskRwHelper.readFromDisk(); } catch (IOException e1) { - Slog.e(TAG, "Failed to read configs from disk; retrying", e1); + logErr("Failed to read configs from disk; retrying", e1); // Retry immediately. The IOException may have been transient. try { configBundle = mConfigDiskRwHelper.readFromDisk(); } catch (IOException e2) { - Slog.wtf(TAG, "Failed to read configs from disk", e2); + logWtf("Failed to read configs from disk", e2); return; } } @@ -442,7 +447,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; - Slog.d(TAG, "new snapshot: " + mLastSnapshot); + logDbg("new snapshot: " + mLastSnapshot); // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { @@ -545,7 +550,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + logDbg("Starting VCN config for subGrp: " + subscriptionGroup); // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. @@ -570,7 +575,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startOrUpdateVcnLocked( @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); + logDbg("Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); @@ -596,7 +601,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!config.getProvisioningPackageName().equals(opPkgName)) { throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); } - Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup); + logDbg("VCN config updated for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); @@ -622,7 +627,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(opPkgName, "opPkgName was null"); - Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); + logDbg("VCN config cleared for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); @@ -685,7 +690,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { VcnConfig::toPersistableBundle); mConfigDiskRwHelper.writeToDisk(bundle); } catch (IOException e) { - Slog.e(TAG, "Failed to save configs to disk", e); + logErr("Failed to save configs to disk", e); throw new ServiceSpecificException(0, "Failed to save configs"); } } @@ -795,7 +800,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { for (int subId : networkCapabilities.getSubscriptionIds()) { // Verify that all subscriptions point to the same group if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { - Slog.wtf(TAG, "Got multiple subscription groups for a single network"); + logWtf("Got multiple subscription groups for a single network"); } subGrp = snapshot.getGroupForSubId(subId); @@ -861,10 +866,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result); - if (VDBG) { - Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + "; and lp: " + linkProperties + "; result = " + policy); - } return policy; }); } @@ -956,14 +959,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) { resultStatus = vcnStatus; } else { - Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus); + logWtf("Unknown VCN status: " + vcnStatus); resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } try { cbInfo.mCallback.onVcnStatusChanged(resultStatus); } catch (RemoteException e) { - Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); + logDbg("VcnStatusCallback threw on VCN status change", e); } } } finally { @@ -991,6 +994,43 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, msg); + LOCAL_LOG.log(TAG + " VDBG: " + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, msg); + LOCAL_LOG.log(TAG + " DBG: " + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, msg, tr); + LOCAL_LOG.log(TAG + " DBG: " + msg + tr); + } + + private void logErr(String msg) { + Slog.e(TAG, msg); + LOCAL_LOG.log(TAG + " ERR: " + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, msg, tr); + LOCAL_LOG.log(TAG + " ERR: " + msg + tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, msg); + LOCAL_LOG.log(TAG + " WTF: " + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, msg, tr); + LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + } + /** * Dumps the state of the VcnManagementService for logging and debugging purposes. * @@ -1031,6 +1071,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { pw.decreaseIndent(); pw.println(); } + + pw.println("Local log:"); + pw.increaseIndent(); + LOCAL_LOG.dump(pw); + pw.decreaseIndent(); + pw.println(); }, DUMP_TIMEOUT_MILLIS); } diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 5565ccb6cf..fca706b707 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -39,7 +39,6 @@ import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -222,12 +221,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { if (SubscriptionManager.isValidSubscriptionId(subId)) { final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) { - Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId)); mReadySubIdsBySlotId.put(slotId, subId); handleSubscriptionsChanged(); } } else { - Slog.v(TAG, "Slot unloaded: " + slotId); mReadySubIdsBySlotId.remove(slotId); handleSubscriptionsChanged(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 92a4eededd..ee7bf5f0d9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -20,6 +20,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import static com.android.server.VcnManagementService.LOCAL_LOG; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; @@ -425,7 +427,7 @@ public class UnderlyingNetworkTracker { private static boolean isOpportunistic( @NonNull TelephonySubscriptionSnapshot snapshot, Set subIds) { if (snapshot == null) { - Slog.wtf(TAG, "Got null snapshot"); + logWtf("Got null snapshot"); return false; } @@ -496,7 +498,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got capabilities change for unknown key: " + network); + logWtf("Got capabilities change for unknown key: " + network); return; } @@ -512,7 +514,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got link properties change for unknown key: " + network); + logWtf("Got link properties change for unknown key: " + network); return; } @@ -527,7 +529,7 @@ public class UnderlyingNetworkTracker { final UnderlyingNetworkRecord.Builder builder = mUnderlyingNetworkRecordBuilders.get(network); if (builder == null) { - Slog.wtf(TAG, "Got blocked status change for unknown key: " + network); + logWtf("Got blocked status change for unknown key: " + network); return; } @@ -615,7 +617,7 @@ public class UnderlyingNetworkTracker { // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED if (isBlocked) { - Slog.wtf(TAG, "Network blocked for System Server: " + network); + logWtf("Network blocked for System Server: " + network); return PRIORITY_ANY; } @@ -762,6 +764,16 @@ public class UnderlyingNetworkTracker { } } + private static void logWtf(String msg) { + Slog.wtf(TAG, msg); + LOCAL_LOG.log(TAG + " WTF: " + msg); + } + + private static void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, msg, tr); + LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + } + /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkTracker:"); diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 6b4ee693c9..f7d61367c8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -513,37 +514,44 @@ public class Vcn extends Handler { } private String getLogPrefix() { - return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: "; + return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] "; } private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 54a1da0752..493697049f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -30,6 +30,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; +import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -1644,7 +1645,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform transform, int direction) { if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) { - Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction); + logWtf("Applying transform for unexpected direction: " + direction); } try { @@ -2133,37 +2134,44 @@ public class VcnGatewayConnection extends StateMachine { + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + mConnectionConfig.getGatewayConnectionName() - + "]: "; + + "] "; } private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr); } /** diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 8adcf95e78..ebabe2a664 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -105,6 +105,10 @@ public class VcnNetworkProvider extends NetworkProvider { @Override public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + if (VDBG) { + Slog.v(TAG, "Network request withdrawn: Request = " + request); + } + mRequests.remove(request); } From 9537a305170f2d309ad366f71928ac9a620eca27 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 19 May 2021 22:44:47 +0000 Subject: [PATCH 0233/1057] Remove underlying network caps This change removes unused fields in the persistable bundle and VcnGatewayConnectionConfig classes to ensure future flexibility. Bug: 182219992 Test: atest FrameworksVcnTests Change-Id: Ic2fec8a87fd19a1780333c61759c4092598d349e Merged-In: Ic2fec8a87fd19a1780333c61759c4092598d349e (cherry picked from commit 80b15ec764ecbf3aed060c67adea37a7ef3cbb70) --- .../net/vcn/VcnGatewayConnectionConfig.java | 93 ------------------- .../server/vcn/UnderlyingNetworkTracker.java | 8 -- .../server/vcn/VcnGatewayConnection.java | 3 - .../vcn/VcnGatewayConnectionConfigTest.java | 12 +-- .../vcn/UnderlyingNetworkTrackerTest.java | 3 - .../vcn/VcnGatewayConnectionTestBase.java | 2 +- 6 files changed, 2 insertions(+), 119 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 7eea0b1129..86cd23d1e9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -166,9 +166,6 @@ public final class VcnGatewayConnectionConfig { private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; - private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; - @NonNull private final SortedSet mUnderlyingCapabilities; - private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -180,13 +177,11 @@ public final class VcnGatewayConnectionConfig { @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, - @NonNull Set underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); - mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; @@ -203,16 +198,12 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); - final PersistableBundle underlyingCapsBundle = - in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( - underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -311,36 +302,6 @@ public final class VcnGatewayConnectionConfig { return Collections.unmodifiableSet(mExposedCapabilities); } - /** - * Returns all capabilities required of underlying networks. - * - *

      The returned integer-value capabilities will be sorted in ascending numerical order. - * - * @see Builder#addRequiredUnderlyingCapability(int) - * @see Builder#removeRequiredUnderlyingCapability(int) - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public int[] getRequiredUnderlyingCapabilities() { - // Sorted set guarantees ordering - return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities)); - } - - /** - * Returns all capabilities required of underlying networks. - * - *

      Left to prevent the need to make major changes while changes are actively in flight. - * - * @deprecated use getRequiredUnderlyingCapabilities() instead - * @hide - */ - @Deprecated - @NonNull - public Set getAllUnderlyingCapabilities() { - return Collections.unmodifiableSet(mUnderlyingCapabilities); - } - /** * Retrieves the configured retry intervals. * @@ -377,15 +338,10 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); - final PersistableBundle underlyingCapsBundle = - PersistableBundleUtils.fromList( - new ArrayList<>(mUnderlyingCapabilities), - PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); - result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -397,7 +353,6 @@ public final class VcnGatewayConnectionConfig { return Objects.hash( mGatewayConnectionName, mExposedCapabilities, - mUnderlyingCapabilities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); } @@ -411,7 +366,6 @@ public final class VcnGatewayConnectionConfig { final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mExposedCapabilities.equals(rhs.mExposedCapabilities) - && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; } @@ -423,7 +377,6 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); - @NonNull private final Set mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; @@ -494,51 +447,6 @@ public final class VcnGatewayConnectionConfig { return this; } - /** - * Require a capability for Networks underlying this VCN Gateway Connection. - * - * @param underlyingCapability the capability that a network MUST have in order to be an - * underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public Builder addRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.add(underlyingCapability); - return this; - } - - /** - * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection. - * - *

      Calling this method will allow Networks that do NOT have this capability to be - * selected as an underlying network for this VCN Gateway Connection. However, underlying - * networks MAY still have the removed capability. - * - * @param underlyingCapability the capability that a network DOES NOT need to have in order - * to be an underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap - public Builder removeRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.remove(underlyingCapability); - return this; - } - /** * Set the retry interval between VCN establishment attempts upon successive failures. * @@ -603,7 +511,6 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, - mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); } diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index 5414a5206a..92a4eededd 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -120,7 +120,6 @@ public class UnderlyingNetworkTracker { @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; - @NonNull private final Set mRequiredUnderlyingNetworkCapabilities; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @@ -145,13 +144,11 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb) { this( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, cb, new Dependencies()); } @@ -160,16 +157,11 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); - mRequiredUnderlyingNetworkCapabilities = - Objects.requireNonNull( - requiredUnderlyingNetworkCapabilities, - "Missing requiredUnderlyingNetworkCapabilities"); mCb = Objects.requireNonNull(cb, "Missing cb"); mDeps = Objects.requireNonNull(deps, "Missing deps"); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index fbbae97353..54a1da0752 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -673,7 +673,6 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext, subscriptionGroup, mLastSnapshot, - mConnectionConfig.getAllUnderlyingCapabilities(), mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); @@ -2287,13 +2286,11 @@ public class VcnGatewayConnection extends StateMachine { VcnContext vcnContext, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - Set requiredUnderlyingNetworkCapabilities, UnderlyingNetworkTrackerCallback callback) { return new UnderlyingNetworkTracker( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, callback); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index c59dcf879b..4ce78aa4d8 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -92,10 +92,6 @@ public class VcnGatewayConnectionConfigTest { builder.addExposedCapability(caps); } - for (int caps : UNDERLYING_CAPS) { - builder.addRequiredUnderlyingCapability(caps); - } - return builder.build(); } @@ -141,9 +137,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyExposedCaps() { try { - newBuilder() - .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); + newBuilder().build(); fail("Expected exception due to invalid exposed capabilities"); } catch (IllegalArgumentException e) { @@ -187,10 +181,6 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); - int[] underlyingCaps = config.getRequiredUnderlyingCapabilities(); - Arrays.sort(underlyingCaps); - assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); - assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index a36fd797d1..f91575b670 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -61,7 +61,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; -import java.util.Collections; import java.util.Set; import java.util.UUID; @@ -146,7 +145,6 @@ public class UnderlyingNetworkTrackerTest { mVcnContext, SUB_GROUP, mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); } @@ -187,7 +185,6 @@ public class UnderlyingNetworkTrackerTest { vcnContext, SUB_GROUP, mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); verify(cm) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 0a4fcbcb28..b97023a95d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -177,7 +177,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any(), any(), any()); + .newUnderlyingNetworkTracker(any(), any(), any(), any()); doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); From 8d59eecf7433e67185b73d21cc705fbb1ddf85f9 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 26 May 2021 11:53:10 -0700 Subject: [PATCH 0234/1057] Allow MANAGE_TEST_NETWORKS to register and get VCN policies. This CL updates VcnManagementService to allow permission MANAGE_TEST_NETWORKS to register/unregister VCN policy listers as well as apply VCN policies. Previously, only permission NETWORK_FACTORY was allowed to perform this operations. Bug: 189125789 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I6ad3a58f4ef87d931917fbd772a810af81b27da1 --- .../android/server/VcnManagementService.java | 29 ++++++++++++++----- .../server/VcnManagementServiceTest.java | 16 +++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 7fb164a339..171805245e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -18,6 +18,7 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; @@ -36,6 +37,7 @@ 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.LinkProperties; import android.net.Network; @@ -73,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.LocationPermissionChecker; +import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; @@ -741,9 +744,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY to register a policy listener"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); Binder.withCleanCallingIdentity(() -> { PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); @@ -768,9 +772,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY to unregister a policy listener"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { @@ -821,10 +826,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { requireNonNull(networkCapabilities, "networkCapabilities was null"); requireNonNull(linkProperties, "linkProperties was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" - + " Network policies"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); + + final boolean isUsingManageTestNetworks = + mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_FACTORY) + != PackageManager.PERMISSION_GRANTED; + + if (isUsingManageTestNetworks && !networkCapabilities.hasTransport(TRANSPORT_TEST)) { + throw new IllegalStateException( + "NetworkCapabilities must be for Test Network if using permission" + + " MANAGE_TEST_NETWORKS"); + } return Binder.withCleanCallingIdentity(() -> { // Defensive copy in case this call is in-process and the given NetworkCapabilities diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 3360d40062..b7a6d0ff76 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -57,6 +57,7 @@ import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; @@ -707,10 +708,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } @@ -724,10 +724,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } @@ -919,10 +918,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testGetUnderlyingNetworkPolicyInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties()); } From 16928aba55cd216f8d8d4309b5588edd219948b4 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 11 Jun 2021 00:07:21 +0000 Subject: [PATCH 0235/1057] Allow MANAGE_TEST_NETWORKS to register and get VCN policies. This CL updates VcnManagementService to allow permission MANAGE_TEST_NETWORKS to register/unregister VCN policy listers as well as apply VCN policies. Previously, only permission NETWORK_FACTORY was allowed to perform this operations. Bug: 189125789 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I6ad3a58f4ef87d931917fbd772a810af81b27da1 Merged-In: I6ad3a58f4ef87d931917fbd772a810af81b27da1 (cherry picked from commit b760062cee63ee13484de62abd471956305989c3) --- .../android/server/VcnManagementService.java | 29 ++++++++++++++----- .../server/VcnManagementServiceTest.java | 16 +++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 7e2274b65f..f9fd108176 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -18,6 +18,7 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; @@ -36,6 +37,7 @@ 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.LinkProperties; import android.net.Network; @@ -73,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.LocationPermissionChecker; +import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; @@ -739,9 +742,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY to register a policy listener"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); Binder.withCleanCallingIdentity(() -> { PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); @@ -766,9 +770,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY to unregister a policy listener"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { @@ -819,10 +824,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { requireNonNull(networkCapabilities, "networkCapabilities was null"); requireNonNull(linkProperties, "linkProperties was null"); - mContext.enforceCallingOrSelfPermission( + PermissionUtils.enforceAnyPermissionOf( + mContext, android.Manifest.permission.NETWORK_FACTORY, - "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" - + " Network policies"); + android.Manifest.permission.MANAGE_TEST_NETWORKS); + + final boolean isUsingManageTestNetworks = + mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_FACTORY) + != PackageManager.PERMISSION_GRANTED; + + if (isUsingManageTestNetworks && !networkCapabilities.hasTransport(TRANSPORT_TEST)) { + throw new IllegalStateException( + "NetworkCapabilities must be for Test Network if using permission" + + " MANAGE_TEST_NETWORKS"); + } return Binder.withCleanCallingIdentity(() -> { // Defensive copy in case this call is in-process and the given NetworkCapabilities diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 3360d40062..b7a6d0ff76 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -57,6 +57,7 @@ import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; @@ -707,10 +708,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } @@ -724,10 +724,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } @@ -919,10 +918,9 @@ public class VcnManagementServiceTest { @Test(expected = SecurityException.class) public void testGetUnderlyingNetworkPolicyInvalidPermission() { - doThrow(new SecurityException()) + doReturn(PackageManager.PERMISSION_DENIED) .when(mMockContext) - .enforceCallingOrSelfPermission( - eq(android.Manifest.permission.NETWORK_FACTORY), any()); + .checkCallingOrSelfPermission(any()); mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties()); } From a0b6ac2e856fe18d09c83bab6b760da53211f386 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 7 Apr 2021 20:38:48 -0700 Subject: [PATCH 0236/1057] CTS test VCN Network Policies with Test Networks. This CL adds CTS testing to make sure that Test Networks are marked as VCN-managed when they have a subId that belongs to a subscription group of a configured VCN. This CL also defines a TestNetworkAgent for testing VCN APIs. Specifically, this NetworkAgent is used to create a TUN Network associated with a TestNetworkInterface. TestNetworkAgents will also listen for VCN Network policies. Bug: 182291467 Bug: 189125789 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Ia7a256be4be949f1cd90ea98183990591a760f86 --- Vcn/tests/cts/Android.bp | 1 + Vcn/tests/cts/AndroidManifest.xml | 2 + .../net/vcn/cts/TestNetworkWrapper.java | 405 ++++++++++++++++++ .../android/net/vcn/cts/VcnManagerTest.java | 92 ++++ 4 files changed, 500 insertions(+) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index ecb1236b9b..3aed5d72ce 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -34,6 +34,7 @@ android_test { static_libs: [ "androidx.test.ext.junit", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "net-tests-utils", "telephony-cts-utils", diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ba6cc45401..ac0625cc5e 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -21,6 +21,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java new file mode 100644 index 0000000000..6d0a95743e --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -0,0 +1,405 @@ +/* + * 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 android.net.vcn.cts; + +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 android.annotation.NonNull; +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.NetworkAgent; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkProvider; +import android.net.NetworkRequest; +import android.net.RouteInfo; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.TestNetworkSpecifier; +import android.net.vcn.VcnManager; +import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; +import android.net.vcn.VcnNetworkPolicyResult; +import android.os.Looper; +import android.os.ParcelFileDescriptor; +import android.util.CloseGuard; +import android.util.Log; + +import com.android.net.module.util.NetworkStackConstants; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** Utility class for cleanly creating and tearing down Test Networks. */ +// TODO(b/188462344): compine with IKEv2's TestNetworkContext +public class TestNetworkWrapper implements AutoCloseable { + private static final String TAG = TestNetworkWrapper.class.getSimpleName(); + private static final String NETWORK_AGENT_TAG = TestNetworkAgent.class.getSimpleName(); + private static final String POLICY_LISTENER_TAG = + TestNetworkAgent.TestVcnNetworkPolicyChangeListener.class.getSimpleName(); + + public static final int NETWORK_CB_TIMEOUT_MS = 5000; + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 64; + + // This NetworkRequest is expected to only match with Test Networks. To do so, remove all + // default Capabilities and specify TRANSPORT_TEST. + private static final NetworkRequest TEST_NETWORK_REQUEST = + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build(); + + private static final String NETWORK_PROVIDER_NAME = "TestNetworkProvider"; + private static final int TEST_NETWORK_SCORE = 1; // Use a low, non-zero score. + private static final Executor INLINE_EXECUTOR = Runnable::run; + + private final CloseGuard mCloseGuard = new CloseGuard(); + + private final ConnectivityManager mConnectivityManager; + private final VcnManager mVcnManager; + private final TestNetworkManager mTestNetworkManager; + + private final TestNetworkAgent mTestNetworkAgent; + + public final VcnTestNetworkCallback vcnNetworkCallback; + public final ParcelFileDescriptor tunFd; + public final Network tunNetwork; + + public TestNetworkWrapper( + @NonNull Context context, + int mtu, + boolean isMetered, + @NonNull Set subIds, + @NonNull InetAddress localAddress) + throws Exception { + mConnectivityManager = context.getSystemService(ConnectivityManager.class); + mVcnManager = context.getSystemService(VcnManager.class); + mTestNetworkManager = + callWithShellPermissionIdentity( + () -> context.getSystemService(TestNetworkManager.class)); + + try { + final LinkAddress linkAddress = + new LinkAddress( + localAddress, + localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN); + final TestNetworkInterface tni = + callWithShellPermissionIdentity( + () -> { + return mTestNetworkManager.createTunInterface( + Arrays.asList(linkAddress)); + }); + tunFd = tni.getFileDescriptor(); + final String iface = tni.getInterfaceName(); + + vcnNetworkCallback = + callWithShellPermissionIdentity( + () -> { + final NetworkRequest nr = + new NetworkRequest.Builder(TEST_NETWORK_REQUEST) + .setNetworkSpecifier(iface) + .build(); + final VcnTestNetworkCallback cb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(nr, cb); + return cb; + }); + + final NetworkCapabilities nc = + createNetworkCapabilitiesForIface(iface, isMetered, subIds); + final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); + + mTestNetworkAgent = + callWithShellPermissionIdentity( + () -> { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy(nc, lp); + if (policy.isTeardownRequested()) { + throw new IllegalStateException("Restart requested in bringup"); + } + + final TestNetworkAgent agent = + new TestNetworkAgent( + context, + Looper.getMainLooper(), + policy.getNetworkCapabilities(), + lp); + agent.register(); + agent.markConnected(); + return agent; + }); + + tunNetwork = vcnNetworkCallback.waitForAvailable(); + mCloseGuard.open(TAG); + } catch (Exception e) { + close(); + throw e; + } + } + + private static NetworkCapabilities createNetworkCapabilitiesForIface( + @NonNull String iface, boolean isMetered, Set subIds) { + NetworkCapabilities.Builder builder = + NetworkCapabilities.Builder.withoutDefaultCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setNetworkSpecifier(new TestNetworkSpecifier(iface)) + .setSubscriptionIds(subIds); + if (!isMetered) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + return builder.build(); + } + + private static LinkProperties createLinkPropertiesForIface(@NonNull String iface, int mtu) + throws Exception { + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(iface); + lp.setMtu(mtu); + + // Find the currently assigned addresses, and add them to LinkProperties + boolean allowIPv4 = false; + boolean allowIPv6 = false; + NetworkInterface netIntf = NetworkInterface.getByName(iface); + Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf); + + for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { + lp.addLinkAddress( + new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength())); + + if (intfAddr.getAddress() instanceof Inet6Address) { + allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress(); + } else if (intfAddr.getAddress() instanceof Inet4Address) { + allowIPv4 = true; + } + } + + // Add global routes (but as non-default, non-internet providing network). Use prefix + // lengths of 0 to match all IP addresses. + if (allowIPv4) { + lp.addRoute( + new RouteInfo( + new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0 /* prefixLength */), + null /* gateway */, + iface, + RouteInfo.RTN_UNICAST)); + } + if (allowIPv6) { + lp.addRoute( + new RouteInfo( + new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0 /* prefixLength */), + null /* gateway */, + iface, + RouteInfo.RTN_UNICAST)); + } + + return lp; + } + + @Override + public void close() { + mCloseGuard.close(); + runWithShellPermissionIdentity( + () -> { + if (vcnNetworkCallback != null) { + try { + mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister Network CB", e); + } + } + + if (mTestNetworkAgent != null) { + synchronized (mTestNetworkAgent) { + try { + mTestNetworkAgent.teardown(); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister TestNetworkAgent", e); + } + } + } + + if (tunNetwork != null) { + try { + mTestNetworkManager.teardownTestNetwork(tunNetwork); + } catch (Exception e) { + Log.e(TAG, "Failed to tear down Test Network", e); + } + } + + if (tunFd != null) { + try { + tunFd.close(); + } catch (Exception e) { + Log.e(TAG, "Failed to close Test Network FD", e); + } + } + }); + } + + @Override + public void finalize() { + mCloseGuard.warnIfOpen(); + close(); + } + + /** + * Test-only NetworkAgent to be used for instrumented TUN Networks. + * + *

      TestNetworkAgent is NOT THREAD SAFE - all accesses should be synchronized. + */ + private class TestNetworkAgent extends NetworkAgent { + private final CloseGuard mCloseGuard = new CloseGuard(); + private final VcnNetworkPolicyChangeListener mPolicyListener = + new TestVcnNetworkPolicyChangeListener(); + + private final LinkProperties mLinkProperties; + + private NetworkCapabilities mNetworkCapabilities; + + private TestNetworkAgent( + @NonNull Context context, + @NonNull Looper looper, + @NonNull NetworkCapabilities nc, + @NonNull LinkProperties lp) { + super( + context, + looper, + NETWORK_AGENT_TAG, + nc, + lp, + TEST_NETWORK_SCORE, + new NetworkAgentConfig.Builder().build(), + new NetworkProvider(context, looper, NETWORK_PROVIDER_NAME)); + + mNetworkCapabilities = nc; + mLinkProperties = lp; + + mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, mPolicyListener); + + mCloseGuard.open(NETWORK_AGENT_TAG); + } + + @Override + public void finalize() { + mCloseGuard.warnIfOpen(); + teardown(); + } + + @Override + public void onNetworkUnwanted() { + // Not guaranteed to be called from the same thread, so synchronize on this. The shell + // is needed for teardown because unregistering the VcnPolicyListener requires + // permission MANAGE_TEST_NETWORKS. + synchronized (this) { + runWithShellPermissionIdentity(() -> teardown()); + } + } + + private void teardown() { + mCloseGuard.close(); + unregister(); + mVcnManager.removeVcnNetworkPolicyChangeListener(mPolicyListener); + } + + private NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + private void updateNetworkCapabilities(@NonNull NetworkCapabilities nc) { + Objects.requireNonNull(nc, "nc must be non-null"); + + mNetworkCapabilities = nc; + sendNetworkCapabilities(mNetworkCapabilities); + } + + private LinkProperties getLinkProperties() { + return mLinkProperties; + } + + private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { + @Override + public void onPolicyChanged() { + runWithShellPermissionIdentity( + () -> { + synchronized (TestNetworkAgent.this) { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy( + mTestNetworkAgent.getNetworkCapabilities(), + mTestNetworkAgent.getLinkProperties()); + if (policy.isTeardownRequested()) { + Log.w( + POLICY_LISTENER_TAG, + "network teardown requested on policy change"); + teardown(); + return; + } + + updateNetworkCapabilities(policy.getNetworkCapabilities()); + } + }); + } + } + } + + /** NetworkCallback to used for tracking test network events. */ + // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities + public static class VcnTestNetworkCallback extends TestNetworkCallback { + private final BlockingQueue mCapabilitiesChangedHistory = + new LinkedBlockingQueue<>(); + + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { + return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public void onCapabilitiesChanged( + @NonNull Network network, @NonNull NetworkCapabilities nc) { + mCapabilitiesChangedHistory.offer(new CapabilitiesChangedEvent(network, nc)); + } + + public class CapabilitiesChangedEvent { + public final Network network; + public final NetworkCapabilities networkCapabilities; + + public CapabilitiesChangedEvent( + @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + this.network = network; + this.networkCapabilities = networkCapabilities; + } + } + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e406815c34..9e6124d3a2 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -17,22 +17,31 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 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.fail; import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; +import android.net.InetAddresses; import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; +import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.cts.util.CarrierPrivilegeUtils; @@ -41,10 +50,13 @@ import android.telephony.cts.util.SubscriptionGroupUtils; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet6Address; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -58,12 +70,19 @@ public class VcnManagerTest extends VcnTestBase { private static final Executor INLINE_EXECUTOR = Runnable::run; + private static final int TEST_NETWORK_MTU = 1500; + + private static final Inet6Address LOCAL_V6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private TestNetworkWrapper mTestNetworkWrapper; + public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); mVcnManager = mContext.getSystemService(VcnManager.class); @@ -77,6 +96,13 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); } + @After + public void tearDown() throws Exception { + if (mTestNetworkWrapper != null) { + mTestNetworkWrapper.close(); + } + } + private VcnConfig buildVcnConfig() { return new VcnConfig.Builder(mContext) .addGatewayConnectionConfig( @@ -269,4 +295,70 @@ public class VcnManagerTest extends VcnTestBase { mVcnManager.unregisterVcnStatusCallback(callback); } + + @Test + public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */); + + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + false /* expectNotVcnManaged */, + false /* expectNotMetered */); + + mVcnManager.clearVcnConfig(subGrp); + + // After the VCN tears down, the test network should have + // NOT_VCN_MANAGED again + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */); + }); + }); + } + + private void verifyExpectedUnderlyingNetworkCapabilities( + boolean expectNotVcnManaged, boolean expectNotMetered) throws Exception { + final long start = SystemClock.elapsedRealtime(); + + // Wait for NetworkCapabilities changes until they match the expected capabilities + do { + final CapabilitiesChangedEvent capabilitiesChangedEvent = + mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged(); + assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent); + + final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities; + if (mTestNetworkWrapper.tunNetwork.equals(capabilitiesChangedEvent.network) + && nc.hasCapability(NET_CAPABILITY_VALIDATED) + && expectNotVcnManaged == nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) { + return; + } + } while (SystemClock.elapsedRealtime() - start < TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + + fail( + "Expected update for network=" + + mTestNetworkWrapper.tunNetwork.getNetId() + + ". Wanted NOT_VCN_MANAGED=" + + expectNotVcnManaged + + " NOT_METERED=" + + expectNotMetered); + } } From 5ee7ee487b02a1f68ece7c03fdf671b5b301768d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 26 May 2021 18:00:38 -0700 Subject: [PATCH 0237/1057] Test VCN policies for test Networks with test permissions. This CL adds CTS coverage to verify that getting VCN network policies with permission MANAGE_TEST_NETWORKS requires the Network to have TRANSPORT_TEST. Bug: 182291467 Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: I8463c78d463dee482227abfdbe9c32b1c617de55 --- .../android/net/vcn/cts/VcnManagerTest.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9e6124d3a2..9bf818ddab 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -18,11 +18,13 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +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.assertNotEquals; @@ -196,6 +198,24 @@ public class VcnManagerTest extends VcnTestBase { mVcnManager.applyVcnNetworkPolicy(nc, lp); } + @Test + public void testApplyVcnNetworkPolicy_manageTestNetworkRequiresTransportTest() + throws Exception { + final NetworkCapabilities nc = + new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final LinkProperties lp = new LinkProperties(); + + runWithShellPermissionIdentity( + () -> { + try { + mVcnManager.applyVcnNetworkPolicy(nc, lp); + fail("Expected IllegalStateException for applyVcnNetworkPolicy"); + } catch (IllegalStateException e) { + } + }, + android.Manifest.permission.MANAGE_TEST_NETWORKS); + } + /** Test implementation of VcnStatusCallback for verification purposes. */ private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { private final CompletableFuture mFutureOnStatusChanged = From 49e82e17bb453006f32d8c4e2b9f26b2171a63a5 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Tue, 15 Jun 2021 13:54:24 -0700 Subject: [PATCH 0238/1057] Convert VcnNetworkProvider to use NetworkOffers This change brings VcnNetworkProvider to full functionality in the new NetworkProvider paradigm, where NetworkProviders offer networks, and are notified based on NetworkOfferCallbacks. Bug: 185204197 Test: atest FrameworksVcnTests Change-Id: I88c69c0be9f6fd81839fb1595ed00341001694a5 Merged-In: I88c69c0be9f6fd81839fb1595ed00341001694a5 --- .../net/vcn/VcnGatewayConnectionConfig.java | 7 +- .../android/server/VcnManagementService.java | 3 +- .../server/vcn/VcnNetworkProvider.java | 93 +++++++++++++++++-- .../server/vcn/VcnNetworkProviderTest.java | 51 +++++++++- 4 files changed, 140 insertions(+), 14 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index d59ad6f888..86cd23d1e9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -83,7 +83,12 @@ public final class VcnGatewayConnectionConfig { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int MIN_MTU_V6 = 1280; - private static final Set ALLOWED_CAPABILITIES; + /** + * The set of allowed capabilities for exposed capabilities. + * + * @hide + */ + public static final Set ALLOWED_CAPABILITIES; static { Set allowedCaps = new ArraySet<>(); diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 171805245e..70b0fc126e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -372,8 +372,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkProvider(mNetworkProvider); + mNetworkProvider.register(); mContext.getSystemService(ConnectivityManager.class) .registerNetworkCallback( new NetworkRequest.Builder().clearCapabilities().build(), diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index ebabe2a664..31ee2477fa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -16,12 +16,24 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +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 com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; +import android.net.NetworkScore; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; import android.util.Slog; @@ -30,7 +42,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.Executor; /** * VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed. @@ -45,6 +59,10 @@ public class VcnNetworkProvider extends NetworkProvider { private final Set mListeners = new ArraySet<>(); + private final Context mContext; + private final Handler mHandler; + private final Dependencies mDeps; + /** * Cache of NetworkRequest(s). * @@ -52,8 +70,59 @@ public class VcnNetworkProvider extends NetworkProvider { */ private final Set mRequests = new ArraySet<>(); - public VcnNetworkProvider(Context context, Looper looper) { - super(context, looper, VcnNetworkProvider.class.getSimpleName()); + public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { + this(context, looper, new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnNetworkProvider( + @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) { + super( + Objects.requireNonNull(context, "Missing context"), + Objects.requireNonNull(looper, "Missing looper"), + TAG); + + mContext = context; + mHandler = new Handler(looper); + mDeps = Objects.requireNonNull(dependencies, "Missing dependencies"); + } + + /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */ + public void register() { + mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this); + mDeps.registerNetworkOffer( + this, + Vcn.getNetworkScore(), // score filter + buildCapabilityFilter(), + new HandlerExecutor(mHandler), + new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull NetworkRequest request) { + handleNetworkRequested(request); + } + + @Override + public void onNetworkUnneeded(@NonNull NetworkRequest request) { + handleNetworkRequestWithdrawn(request); + } + }); + } + + /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */ + private NetworkCapabilities buildCapabilityFilter() { + final NetworkCapabilities.Builder builder = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_TRUSTED) + .addCapability(NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NET_CAPABILITY_NOT_VPN) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + + for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) { + builder.addCapability(cap); + } + + return builder.build(); } /** @@ -88,8 +157,7 @@ public class VcnNetworkProvider extends NetworkProvider { listener.onNetworkRequested(request); } - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { + private void handleNetworkRequested(@NonNull NetworkRequest request) { if (VDBG) { Slog.v(TAG, "Network requested: Request = " + request); } @@ -103,8 +171,7 @@ public class VcnNetworkProvider extends NetworkProvider { } } - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) { if (VDBG) { Slog.v(TAG, "Network request withdrawn: Request = " + request); } @@ -144,4 +211,18 @@ public class VcnNetworkProvider extends NetworkProvider { pw.decreaseIndent(); } + + /** Proxy class for dependencies used for testing. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Registers a given network offer for the given provider. */ + public void registerNetworkOffer( + @NonNull VcnNetworkProvider provider, + @NonNull NetworkScore score, + @NonNull NetworkCapabilities capabilitiesFilter, + @NonNull Executor executor, + @NonNull NetworkOfferCallback callback) { + provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback); + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index 79cf746f10..72db55b3f4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -16,12 +16,18 @@ package com.android.server.vcn; +import static android.net.NetworkProvider.NetworkOfferCallback; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; import android.net.NetworkRequest; import android.os.test.TestLooper; @@ -33,6 +39,7 @@ import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.List; @@ -47,6 +54,8 @@ public class VcnNetworkProviderTest { @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; + @NonNull private VcnNetworkProvider.Dependencies mDeps; + @NonNull private ConnectivityManager mConnMgr; @NonNull private VcnNetworkProvider mVcnNetworkProvider; @NonNull private NetworkRequestListener mListener; @@ -57,16 +66,47 @@ public class VcnNetworkProviderTest { @Before public void setUp() throws Exception { - mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper()); + mDeps = mock(VcnNetworkProvider.Dependencies.class); + mConnMgr = mock(ConnectivityManager.class); + VcnTestUtils.setupSystemService( + mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + + mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps); mListener = mock(NetworkRequestListener.class); } + private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception { + mVcnNetworkProvider.register(); + + final ArgumentCaptor cbCaptor = + ArgumentCaptor.forClass(NetworkOfferCallback.class); + + verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider)); + verify(mDeps) + .registerNetworkOffer( + eq(mVcnNetworkProvider), + argThat( + score -> + score.getLegacyInt() + == Vcn.getNetworkScore().getLegacyInt()), + any(), + any(), + cbCaptor.capture()); + + return cbCaptor.getValue(); + } + + @Test + public void testRegister() throws Exception { + verifyRegisterAndGetOfferCallback(); + } + @Test public void testRequestsPassedToRegisteredListeners() throws Exception { mVcnNetworkProvider.registerListener(mListener); final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verifyRegisterAndGetOfferCallback().onNetworkNeeded(request); verify(mListener).onNetworkRequested(request); } @@ -76,13 +116,14 @@ public class VcnNetworkProviderTest { mVcnNetworkProvider.unregisterListener(mListener); final NetworkRequest request = mock(NetworkRequest.class); - mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID); + verifyRegisterAndGetOfferCallback().onNetworkNeeded(request); verifyNoMoreInteractions(mListener); } @Test public void testCachedRequestsPassedOnRegister() throws Exception { final List requests = new ArrayList<>(); + final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback(); for (int i = 0; i < 10; i++) { // Build unique network requests; in this case, iterate down the capabilities as a way @@ -91,12 +132,12 @@ public class VcnNetworkProviderTest { new NetworkRequest.Builder().clearCapabilities().addCapability(i).build(); requests.add(request); - mVcnNetworkProvider.onNetworkRequested(request, i, i + 1); + offerCb.onNetworkNeeded(request); } // Remove one, and verify that it is never sent to the listeners. final NetworkRequest removed = requests.remove(0); - mVcnNetworkProvider.onNetworkRequestWithdrawn(removed); + offerCb.onNetworkUnneeded(removed); mVcnNetworkProvider.registerListener(mListener); for (NetworkRequest request : requests) { From fb8fbb8d631f12abd8ee5e42b29cc30d6dd10450 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 14 Jun 2021 12:13:21 -0700 Subject: [PATCH 0239/1057] Adopt and drop shell permission once per VCN test. This CL updates VcnManagerTest to explicitly adopt and drop shell permission identity once per test. This change ensures that no races occur between adopting and dropping shell permission identity in testing, which can cause test flake. This CL also updates CarrierPrivilegeUtils to not manage its own permissions (needed for adopting CarrierPrivileges). Instead, the caller must manage these permissions before using the util. Bug: 182291467 Test: atest CtsVcnTestCases Change-Id: I3e82d3b2da3fe30b87a90751b0b996a42e6f15c3 --- .../net/vcn/cts/TestNetworkWrapper.java | 156 +++++++----------- .../android/net/vcn/cts/VcnManagerTest.java | 21 ++- 2 files changed, 80 insertions(+), 97 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 6d0a95743e..52b6245a18 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -18,9 +18,6 @@ package android.net.vcn.cts; 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 android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager; @@ -106,9 +103,7 @@ public class TestNetworkWrapper implements AutoCloseable { throws Exception { mConnectivityManager = context.getSystemService(ConnectivityManager.class); mVcnManager = context.getSystemService(VcnManager.class); - mTestNetworkManager = - callWithShellPermissionIdentity( - () -> context.getSystemService(TestNetworkManager.class)); + mTestNetworkManager = context.getSystemService(TestNetworkManager.class); try { final LinkAddress linkAddress = @@ -116,49 +111,31 @@ public class TestNetworkWrapper implements AutoCloseable { localAddress, localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN); final TestNetworkInterface tni = - callWithShellPermissionIdentity( - () -> { - return mTestNetworkManager.createTunInterface( - Arrays.asList(linkAddress)); - }); + mTestNetworkManager.createTunInterface(Arrays.asList(linkAddress)); tunFd = tni.getFileDescriptor(); final String iface = tni.getInterfaceName(); - vcnNetworkCallback = - callWithShellPermissionIdentity( - () -> { - final NetworkRequest nr = - new NetworkRequest.Builder(TEST_NETWORK_REQUEST) - .setNetworkSpecifier(iface) - .build(); - final VcnTestNetworkCallback cb = new VcnTestNetworkCallback(); - mConnectivityManager.requestNetwork(nr, cb); - return cb; - }); + final NetworkRequest nr = + new NetworkRequest.Builder(TEST_NETWORK_REQUEST) + .setNetworkSpecifier(iface) + .build(); + vcnNetworkCallback = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(nr, vcnNetworkCallback); final NetworkCapabilities nc = createNetworkCapabilitiesForIface(iface, isMetered, subIds); final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); - mTestNetworkAgent = - callWithShellPermissionIdentity( - () -> { - final VcnNetworkPolicyResult policy = - mVcnManager.applyVcnNetworkPolicy(nc, lp); - if (policy.isTeardownRequested()) { - throw new IllegalStateException("Restart requested in bringup"); - } + final VcnNetworkPolicyResult policy = mVcnManager.applyVcnNetworkPolicy(nc, lp); + if (policy.isTeardownRequested()) { + throw new IllegalStateException("Restart requested in bringup"); + } - final TestNetworkAgent agent = - new TestNetworkAgent( - context, - Looper.getMainLooper(), - policy.getNetworkCapabilities(), - lp); - agent.register(); - agent.markConnected(); - return agent; - }); + mTestNetworkAgent = + new TestNetworkAgent( + context, Looper.getMainLooper(), policy.getNetworkCapabilities(), lp); + mTestNetworkAgent.register(); + mTestNetworkAgent.markConnected(); tunNetwork = vcnNetworkCallback.waitForAvailable(); mCloseGuard.open(TAG); @@ -232,42 +209,40 @@ public class TestNetworkWrapper implements AutoCloseable { @Override public void close() { mCloseGuard.close(); - runWithShellPermissionIdentity( - () -> { - if (vcnNetworkCallback != null) { - try { - mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); - } catch (Exception e) { - Log.e(TAG, "Failed to unregister Network CB", e); - } - } - if (mTestNetworkAgent != null) { - synchronized (mTestNetworkAgent) { - try { - mTestNetworkAgent.teardown(); - } catch (Exception e) { - Log.e(TAG, "Failed to unregister TestNetworkAgent", e); - } - } - } + if (vcnNetworkCallback != null) { + try { + mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister Network CB", e); + } + } - if (tunNetwork != null) { - try { - mTestNetworkManager.teardownTestNetwork(tunNetwork); - } catch (Exception e) { - Log.e(TAG, "Failed to tear down Test Network", e); - } - } + if (mTestNetworkAgent != null) { + synchronized (mTestNetworkAgent) { + try { + mTestNetworkAgent.teardown(); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister TestNetworkAgent", e); + } + } + } - if (tunFd != null) { - try { - tunFd.close(); - } catch (Exception e) { - Log.e(TAG, "Failed to close Test Network FD", e); - } - } - }); + if (tunNetwork != null) { + try { + mTestNetworkManager.teardownTestNetwork(tunNetwork); + } catch (Exception e) { + Log.e(TAG, "Failed to tear down Test Network", e); + } + } + + if (tunFd != null) { + try { + tunFd.close(); + } catch (Exception e) { + Log.e(TAG, "Failed to close Test Network FD", e); + } + } } @Override @@ -321,11 +296,9 @@ public class TestNetworkWrapper implements AutoCloseable { @Override public void onNetworkUnwanted() { - // Not guaranteed to be called from the same thread, so synchronize on this. The shell - // is needed for teardown because unregistering the VcnPolicyListener requires - // permission MANAGE_TEST_NETWORKS. + // Not guaranteed to be called from the same thread, so synchronize on this. synchronized (this) { - runWithShellPermissionIdentity(() -> teardown()); + teardown(); } } @@ -353,24 +326,19 @@ public class TestNetworkWrapper implements AutoCloseable { private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { @Override public void onPolicyChanged() { - runWithShellPermissionIdentity( - () -> { - synchronized (TestNetworkAgent.this) { - final VcnNetworkPolicyResult policy = - mVcnManager.applyVcnNetworkPolicy( - mTestNetworkAgent.getNetworkCapabilities(), - mTestNetworkAgent.getLinkProperties()); - if (policy.isTeardownRequested()) { - Log.w( - POLICY_LISTENER_TAG, - "network teardown requested on policy change"); - teardown(); - return; - } + synchronized (TestNetworkAgent.this) { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy( + mTestNetworkAgent.getNetworkCapabilities(), + mTestNetworkAgent.getLinkProperties()); + if (policy.isTeardownRequested()) { + Log.w(POLICY_LISTENER_TAG, "network teardown requested on policy change"); + teardown(); + return; + } - updateNetworkCapabilities(policy.getNetworkCapabilities()); - } - }); + updateNetworkCapabilities(policy.getNetworkCapabilities()); + } } } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9bf818ddab..7fec0011b0 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -23,6 +23,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertEquals; @@ -96,12 +98,19 @@ public class VcnManagerTest extends VcnTestBase { @Before public void setUp() throws Exception { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); + + getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); } @After public void tearDown() throws Exception { - if (mTestNetworkWrapper != null) { - mTestNetworkWrapper.close(); + try { + if (mTestNetworkWrapper != null) { + mTestNetworkWrapper.close(); + mTestNetworkWrapper = null; + } + } finally { + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } } @@ -172,6 +181,9 @@ public class VcnManagerTest extends VcnTestBase { @Test(expected = SecurityException.class) public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() throws Exception { + // Drop shell permission identity to test unpermissioned behavior. + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + final TestVcnNetworkPolicyChangeListener listener = new TestVcnNetworkPolicyChangeListener(); @@ -192,6 +204,9 @@ public class VcnManagerTest extends VcnTestBase { @Test(expected = SecurityException.class) public void testApplyVcnNetworkPolicy_noNetworkFactoryPermission() throws Exception { + // Drop shell permission identity to test unpermissioned behavior. + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + final NetworkCapabilities nc = new NetworkCapabilities.Builder().build(); final LinkProperties lp = new LinkProperties(); @@ -334,7 +349,7 @@ public class VcnManagerTest extends VcnTestBase { true /* expectNotVcnManaged */, false /* expectNotMetered */); - CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> { + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); From ba2c5da650766fef50b1950ce7d3ded25dab3c16 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 16 Jun 2021 01:29:54 +0000 Subject: [PATCH 0240/1057] CTS test VCN Network Policies with Test Networks. This CL adds CTS testing to make sure that Test Networks are marked as VCN-managed when they have a subId that belongs to a subscription group of a configured VCN. This CL also defines a TestNetworkAgent for testing VCN APIs. Specifically, this NetworkAgent is used to create a TUN Network associated with a TestNetworkInterface. TestNetworkAgents will also listen for VCN Network policies. Bug: 182291467 Bug: 189125789 Test: atest FrameworksVcnTests CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1672166 Merged-In: Ia7a256be4be949f1cd90ea98183990591a760f86 Change-Id: Ia7a256be4be949f1cd90ea98183990591a760f86 --- Vcn/tests/cts/Android.bp | 1 + Vcn/tests/cts/AndroidManifest.xml | 2 + .../net/vcn/cts/TestNetworkWrapper.java | 405 ++++++++++++++++++ .../android/net/vcn/cts/VcnManagerTest.java | 92 ++++ 4 files changed, 500 insertions(+) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index ecb1236b9b..3aed5d72ce 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -34,6 +34,7 @@ android_test { static_libs: [ "androidx.test.ext.junit", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "net-tests-utils", "telephony-cts-utils", diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ba6cc45401..ac0625cc5e 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -21,6 +21,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java new file mode 100644 index 0000000000..6d0a95743e --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -0,0 +1,405 @@ +/* + * 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 android.net.vcn.cts; + +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 android.annotation.NonNull; +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.NetworkAgent; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkProvider; +import android.net.NetworkRequest; +import android.net.RouteInfo; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.TestNetworkSpecifier; +import android.net.vcn.VcnManager; +import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; +import android.net.vcn.VcnNetworkPolicyResult; +import android.os.Looper; +import android.os.ParcelFileDescriptor; +import android.util.CloseGuard; +import android.util.Log; + +import com.android.net.module.util.NetworkStackConstants; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** Utility class for cleanly creating and tearing down Test Networks. */ +// TODO(b/188462344): compine with IKEv2's TestNetworkContext +public class TestNetworkWrapper implements AutoCloseable { + private static final String TAG = TestNetworkWrapper.class.getSimpleName(); + private static final String NETWORK_AGENT_TAG = TestNetworkAgent.class.getSimpleName(); + private static final String POLICY_LISTENER_TAG = + TestNetworkAgent.TestVcnNetworkPolicyChangeListener.class.getSimpleName(); + + public static final int NETWORK_CB_TIMEOUT_MS = 5000; + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 64; + + // This NetworkRequest is expected to only match with Test Networks. To do so, remove all + // default Capabilities and specify TRANSPORT_TEST. + private static final NetworkRequest TEST_NETWORK_REQUEST = + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build(); + + private static final String NETWORK_PROVIDER_NAME = "TestNetworkProvider"; + private static final int TEST_NETWORK_SCORE = 1; // Use a low, non-zero score. + private static final Executor INLINE_EXECUTOR = Runnable::run; + + private final CloseGuard mCloseGuard = new CloseGuard(); + + private final ConnectivityManager mConnectivityManager; + private final VcnManager mVcnManager; + private final TestNetworkManager mTestNetworkManager; + + private final TestNetworkAgent mTestNetworkAgent; + + public final VcnTestNetworkCallback vcnNetworkCallback; + public final ParcelFileDescriptor tunFd; + public final Network tunNetwork; + + public TestNetworkWrapper( + @NonNull Context context, + int mtu, + boolean isMetered, + @NonNull Set subIds, + @NonNull InetAddress localAddress) + throws Exception { + mConnectivityManager = context.getSystemService(ConnectivityManager.class); + mVcnManager = context.getSystemService(VcnManager.class); + mTestNetworkManager = + callWithShellPermissionIdentity( + () -> context.getSystemService(TestNetworkManager.class)); + + try { + final LinkAddress linkAddress = + new LinkAddress( + localAddress, + localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN); + final TestNetworkInterface tni = + callWithShellPermissionIdentity( + () -> { + return mTestNetworkManager.createTunInterface( + Arrays.asList(linkAddress)); + }); + tunFd = tni.getFileDescriptor(); + final String iface = tni.getInterfaceName(); + + vcnNetworkCallback = + callWithShellPermissionIdentity( + () -> { + final NetworkRequest nr = + new NetworkRequest.Builder(TEST_NETWORK_REQUEST) + .setNetworkSpecifier(iface) + .build(); + final VcnTestNetworkCallback cb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(nr, cb); + return cb; + }); + + final NetworkCapabilities nc = + createNetworkCapabilitiesForIface(iface, isMetered, subIds); + final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); + + mTestNetworkAgent = + callWithShellPermissionIdentity( + () -> { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy(nc, lp); + if (policy.isTeardownRequested()) { + throw new IllegalStateException("Restart requested in bringup"); + } + + final TestNetworkAgent agent = + new TestNetworkAgent( + context, + Looper.getMainLooper(), + policy.getNetworkCapabilities(), + lp); + agent.register(); + agent.markConnected(); + return agent; + }); + + tunNetwork = vcnNetworkCallback.waitForAvailable(); + mCloseGuard.open(TAG); + } catch (Exception e) { + close(); + throw e; + } + } + + private static NetworkCapabilities createNetworkCapabilitiesForIface( + @NonNull String iface, boolean isMetered, Set subIds) { + NetworkCapabilities.Builder builder = + NetworkCapabilities.Builder.withoutDefaultCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setNetworkSpecifier(new TestNetworkSpecifier(iface)) + .setSubscriptionIds(subIds); + if (!isMetered) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + return builder.build(); + } + + private static LinkProperties createLinkPropertiesForIface(@NonNull String iface, int mtu) + throws Exception { + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(iface); + lp.setMtu(mtu); + + // Find the currently assigned addresses, and add them to LinkProperties + boolean allowIPv4 = false; + boolean allowIPv6 = false; + NetworkInterface netIntf = NetworkInterface.getByName(iface); + Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf); + + for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { + lp.addLinkAddress( + new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength())); + + if (intfAddr.getAddress() instanceof Inet6Address) { + allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress(); + } else if (intfAddr.getAddress() instanceof Inet4Address) { + allowIPv4 = true; + } + } + + // Add global routes (but as non-default, non-internet providing network). Use prefix + // lengths of 0 to match all IP addresses. + if (allowIPv4) { + lp.addRoute( + new RouteInfo( + new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0 /* prefixLength */), + null /* gateway */, + iface, + RouteInfo.RTN_UNICAST)); + } + if (allowIPv6) { + lp.addRoute( + new RouteInfo( + new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0 /* prefixLength */), + null /* gateway */, + iface, + RouteInfo.RTN_UNICAST)); + } + + return lp; + } + + @Override + public void close() { + mCloseGuard.close(); + runWithShellPermissionIdentity( + () -> { + if (vcnNetworkCallback != null) { + try { + mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister Network CB", e); + } + } + + if (mTestNetworkAgent != null) { + synchronized (mTestNetworkAgent) { + try { + mTestNetworkAgent.teardown(); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister TestNetworkAgent", e); + } + } + } + + if (tunNetwork != null) { + try { + mTestNetworkManager.teardownTestNetwork(tunNetwork); + } catch (Exception e) { + Log.e(TAG, "Failed to tear down Test Network", e); + } + } + + if (tunFd != null) { + try { + tunFd.close(); + } catch (Exception e) { + Log.e(TAG, "Failed to close Test Network FD", e); + } + } + }); + } + + @Override + public void finalize() { + mCloseGuard.warnIfOpen(); + close(); + } + + /** + * Test-only NetworkAgent to be used for instrumented TUN Networks. + * + *

      TestNetworkAgent is NOT THREAD SAFE - all accesses should be synchronized. + */ + private class TestNetworkAgent extends NetworkAgent { + private final CloseGuard mCloseGuard = new CloseGuard(); + private final VcnNetworkPolicyChangeListener mPolicyListener = + new TestVcnNetworkPolicyChangeListener(); + + private final LinkProperties mLinkProperties; + + private NetworkCapabilities mNetworkCapabilities; + + private TestNetworkAgent( + @NonNull Context context, + @NonNull Looper looper, + @NonNull NetworkCapabilities nc, + @NonNull LinkProperties lp) { + super( + context, + looper, + NETWORK_AGENT_TAG, + nc, + lp, + TEST_NETWORK_SCORE, + new NetworkAgentConfig.Builder().build(), + new NetworkProvider(context, looper, NETWORK_PROVIDER_NAME)); + + mNetworkCapabilities = nc; + mLinkProperties = lp; + + mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, mPolicyListener); + + mCloseGuard.open(NETWORK_AGENT_TAG); + } + + @Override + public void finalize() { + mCloseGuard.warnIfOpen(); + teardown(); + } + + @Override + public void onNetworkUnwanted() { + // Not guaranteed to be called from the same thread, so synchronize on this. The shell + // is needed for teardown because unregistering the VcnPolicyListener requires + // permission MANAGE_TEST_NETWORKS. + synchronized (this) { + runWithShellPermissionIdentity(() -> teardown()); + } + } + + private void teardown() { + mCloseGuard.close(); + unregister(); + mVcnManager.removeVcnNetworkPolicyChangeListener(mPolicyListener); + } + + private NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + private void updateNetworkCapabilities(@NonNull NetworkCapabilities nc) { + Objects.requireNonNull(nc, "nc must be non-null"); + + mNetworkCapabilities = nc; + sendNetworkCapabilities(mNetworkCapabilities); + } + + private LinkProperties getLinkProperties() { + return mLinkProperties; + } + + private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { + @Override + public void onPolicyChanged() { + runWithShellPermissionIdentity( + () -> { + synchronized (TestNetworkAgent.this) { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy( + mTestNetworkAgent.getNetworkCapabilities(), + mTestNetworkAgent.getLinkProperties()); + if (policy.isTeardownRequested()) { + Log.w( + POLICY_LISTENER_TAG, + "network teardown requested on policy change"); + teardown(); + return; + } + + updateNetworkCapabilities(policy.getNetworkCapabilities()); + } + }); + } + } + } + + /** NetworkCallback to used for tracking test network events. */ + // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities + public static class VcnTestNetworkCallback extends TestNetworkCallback { + private final BlockingQueue mCapabilitiesChangedHistory = + new LinkedBlockingQueue<>(); + + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { + return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public void onCapabilitiesChanged( + @NonNull Network network, @NonNull NetworkCapabilities nc) { + mCapabilitiesChangedHistory.offer(new CapabilitiesChangedEvent(network, nc)); + } + + public class CapabilitiesChangedEvent { + public final Network network; + public final NetworkCapabilities networkCapabilities; + + public CapabilitiesChangedEvent( + @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + this.network = network; + this.networkCapabilities = networkCapabilities; + } + } + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e406815c34..9e6124d3a2 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -17,22 +17,31 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 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.fail; import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; +import android.net.InetAddresses; import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; +import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.cts.util.CarrierPrivilegeUtils; @@ -41,10 +50,13 @@ import android.telephony.cts.util.SubscriptionGroupUtils; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet6Address; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -58,12 +70,19 @@ public class VcnManagerTest extends VcnTestBase { private static final Executor INLINE_EXECUTOR = Runnable::run; + private static final int TEST_NETWORK_MTU = 1500; + + private static final Inet6Address LOCAL_V6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private TestNetworkWrapper mTestNetworkWrapper; + public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); mVcnManager = mContext.getSystemService(VcnManager.class); @@ -77,6 +96,13 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); } + @After + public void tearDown() throws Exception { + if (mTestNetworkWrapper != null) { + mTestNetworkWrapper.close(); + } + } + private VcnConfig buildVcnConfig() { return new VcnConfig.Builder(mContext) .addGatewayConnectionConfig( @@ -269,4 +295,70 @@ public class VcnManagerTest extends VcnTestBase { mVcnManager.unregisterVcnStatusCallback(callback); } + + @Test + public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */); + + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + false /* expectNotVcnManaged */, + false /* expectNotMetered */); + + mVcnManager.clearVcnConfig(subGrp); + + // After the VCN tears down, the test network should have + // NOT_VCN_MANAGED again + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */); + }); + }); + } + + private void verifyExpectedUnderlyingNetworkCapabilities( + boolean expectNotVcnManaged, boolean expectNotMetered) throws Exception { + final long start = SystemClock.elapsedRealtime(); + + // Wait for NetworkCapabilities changes until they match the expected capabilities + do { + final CapabilitiesChangedEvent capabilitiesChangedEvent = + mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged(); + assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent); + + final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities; + if (mTestNetworkWrapper.tunNetwork.equals(capabilitiesChangedEvent.network) + && nc.hasCapability(NET_CAPABILITY_VALIDATED) + && expectNotVcnManaged == nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) { + return; + } + } while (SystemClock.elapsedRealtime() - start < TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + + fail( + "Expected update for network=" + + mTestNetworkWrapper.tunNetwork.getNetId() + + ". Wanted NOT_VCN_MANAGED=" + + expectNotVcnManaged + + " NOT_METERED=" + + expectNotMetered); + } } From 94e5f10723109f41f7a438ad3ced8660dff649ef Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 16 Jun 2021 04:45:16 +0000 Subject: [PATCH 0241/1057] Test VCN policies for test Networks with test permissions. This CL adds CTS coverage to verify that getting VCN network policies with permission MANAGE_TEST_NETWORKS requires the Network to have TRANSPORT_TEST. Bug: 182291467 Bug: 189125789 Test: atest CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1720262 Merged-In: I8463c78d463dee482227abfdbe9c32b1c617de55 Change-Id: I8463c78d463dee482227abfdbe9c32b1c617de55 --- .../android/net/vcn/cts/VcnManagerTest.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9e6124d3a2..9bf818ddab 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -18,11 +18,13 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +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.assertNotEquals; @@ -196,6 +198,24 @@ public class VcnManagerTest extends VcnTestBase { mVcnManager.applyVcnNetworkPolicy(nc, lp); } + @Test + public void testApplyVcnNetworkPolicy_manageTestNetworkRequiresTransportTest() + throws Exception { + final NetworkCapabilities nc = + new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final LinkProperties lp = new LinkProperties(); + + runWithShellPermissionIdentity( + () -> { + try { + mVcnManager.applyVcnNetworkPolicy(nc, lp); + fail("Expected IllegalStateException for applyVcnNetworkPolicy"); + } catch (IllegalStateException e) { + } + }, + android.Manifest.permission.MANAGE_TEST_NETWORKS); + } + /** Test implementation of VcnStatusCallback for verification purposes. */ private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { private final CompletableFuture mFutureOnStatusChanged = From 6901e84c803eabddd373faf413f63d255d3bb8ef Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 17 Jun 2021 17:55:01 +0000 Subject: [PATCH 0242/1057] Adopt and drop shell permission once per VCN test. This CL updates VcnManagerTest to explicitly adopt and drop shell permission identity once per test. This change ensures that no races occur between adopting and dropping shell permission identity in testing, which can cause test flake. This CL also updates CarrierPrivilegeUtils to not manage its own permissions (needed for adopting CarrierPrivileges). Instead, the caller must manage these permissions before using the util. Bug: 182291467 Test: atest CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1737995 Merged-In: I3e82d3b2da3fe30b87a90751b0b996a42e6f15c3 Change-Id: I3e82d3b2da3fe30b87a90751b0b996a42e6f15c3 --- .../net/vcn/cts/TestNetworkWrapper.java | 156 +++++++----------- .../android/net/vcn/cts/VcnManagerTest.java | 21 ++- 2 files changed, 80 insertions(+), 97 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 6d0a95743e..52b6245a18 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -18,9 +18,6 @@ package android.net.vcn.cts; 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 android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager; @@ -106,9 +103,7 @@ public class TestNetworkWrapper implements AutoCloseable { throws Exception { mConnectivityManager = context.getSystemService(ConnectivityManager.class); mVcnManager = context.getSystemService(VcnManager.class); - mTestNetworkManager = - callWithShellPermissionIdentity( - () -> context.getSystemService(TestNetworkManager.class)); + mTestNetworkManager = context.getSystemService(TestNetworkManager.class); try { final LinkAddress linkAddress = @@ -116,49 +111,31 @@ public class TestNetworkWrapper implements AutoCloseable { localAddress, localAddress instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN); final TestNetworkInterface tni = - callWithShellPermissionIdentity( - () -> { - return mTestNetworkManager.createTunInterface( - Arrays.asList(linkAddress)); - }); + mTestNetworkManager.createTunInterface(Arrays.asList(linkAddress)); tunFd = tni.getFileDescriptor(); final String iface = tni.getInterfaceName(); - vcnNetworkCallback = - callWithShellPermissionIdentity( - () -> { - final NetworkRequest nr = - new NetworkRequest.Builder(TEST_NETWORK_REQUEST) - .setNetworkSpecifier(iface) - .build(); - final VcnTestNetworkCallback cb = new VcnTestNetworkCallback(); - mConnectivityManager.requestNetwork(nr, cb); - return cb; - }); + final NetworkRequest nr = + new NetworkRequest.Builder(TEST_NETWORK_REQUEST) + .setNetworkSpecifier(iface) + .build(); + vcnNetworkCallback = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(nr, vcnNetworkCallback); final NetworkCapabilities nc = createNetworkCapabilitiesForIface(iface, isMetered, subIds); final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); - mTestNetworkAgent = - callWithShellPermissionIdentity( - () -> { - final VcnNetworkPolicyResult policy = - mVcnManager.applyVcnNetworkPolicy(nc, lp); - if (policy.isTeardownRequested()) { - throw new IllegalStateException("Restart requested in bringup"); - } + final VcnNetworkPolicyResult policy = mVcnManager.applyVcnNetworkPolicy(nc, lp); + if (policy.isTeardownRequested()) { + throw new IllegalStateException("Restart requested in bringup"); + } - final TestNetworkAgent agent = - new TestNetworkAgent( - context, - Looper.getMainLooper(), - policy.getNetworkCapabilities(), - lp); - agent.register(); - agent.markConnected(); - return agent; - }); + mTestNetworkAgent = + new TestNetworkAgent( + context, Looper.getMainLooper(), policy.getNetworkCapabilities(), lp); + mTestNetworkAgent.register(); + mTestNetworkAgent.markConnected(); tunNetwork = vcnNetworkCallback.waitForAvailable(); mCloseGuard.open(TAG); @@ -232,42 +209,40 @@ public class TestNetworkWrapper implements AutoCloseable { @Override public void close() { mCloseGuard.close(); - runWithShellPermissionIdentity( - () -> { - if (vcnNetworkCallback != null) { - try { - mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); - } catch (Exception e) { - Log.e(TAG, "Failed to unregister Network CB", e); - } - } - if (mTestNetworkAgent != null) { - synchronized (mTestNetworkAgent) { - try { - mTestNetworkAgent.teardown(); - } catch (Exception e) { - Log.e(TAG, "Failed to unregister TestNetworkAgent", e); - } - } - } + if (vcnNetworkCallback != null) { + try { + mConnectivityManager.unregisterNetworkCallback(vcnNetworkCallback); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister Network CB", e); + } + } - if (tunNetwork != null) { - try { - mTestNetworkManager.teardownTestNetwork(tunNetwork); - } catch (Exception e) { - Log.e(TAG, "Failed to tear down Test Network", e); - } - } + if (mTestNetworkAgent != null) { + synchronized (mTestNetworkAgent) { + try { + mTestNetworkAgent.teardown(); + } catch (Exception e) { + Log.e(TAG, "Failed to unregister TestNetworkAgent", e); + } + } + } - if (tunFd != null) { - try { - tunFd.close(); - } catch (Exception e) { - Log.e(TAG, "Failed to close Test Network FD", e); - } - } - }); + if (tunNetwork != null) { + try { + mTestNetworkManager.teardownTestNetwork(tunNetwork); + } catch (Exception e) { + Log.e(TAG, "Failed to tear down Test Network", e); + } + } + + if (tunFd != null) { + try { + tunFd.close(); + } catch (Exception e) { + Log.e(TAG, "Failed to close Test Network FD", e); + } + } } @Override @@ -321,11 +296,9 @@ public class TestNetworkWrapper implements AutoCloseable { @Override public void onNetworkUnwanted() { - // Not guaranteed to be called from the same thread, so synchronize on this. The shell - // is needed for teardown because unregistering the VcnPolicyListener requires - // permission MANAGE_TEST_NETWORKS. + // Not guaranteed to be called from the same thread, so synchronize on this. synchronized (this) { - runWithShellPermissionIdentity(() -> teardown()); + teardown(); } } @@ -353,24 +326,19 @@ public class TestNetworkWrapper implements AutoCloseable { private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { @Override public void onPolicyChanged() { - runWithShellPermissionIdentity( - () -> { - synchronized (TestNetworkAgent.this) { - final VcnNetworkPolicyResult policy = - mVcnManager.applyVcnNetworkPolicy( - mTestNetworkAgent.getNetworkCapabilities(), - mTestNetworkAgent.getLinkProperties()); - if (policy.isTeardownRequested()) { - Log.w( - POLICY_LISTENER_TAG, - "network teardown requested on policy change"); - teardown(); - return; - } + synchronized (TestNetworkAgent.this) { + final VcnNetworkPolicyResult policy = + mVcnManager.applyVcnNetworkPolicy( + mTestNetworkAgent.getNetworkCapabilities(), + mTestNetworkAgent.getLinkProperties()); + if (policy.isTeardownRequested()) { + Log.w(POLICY_LISTENER_TAG, "network teardown requested on policy change"); + teardown(); + return; + } - updateNetworkCapabilities(policy.getNetworkCapabilities()); - } - }); + updateNetworkCapabilities(policy.getNetworkCapabilities()); + } } } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9bf818ddab..7fec0011b0 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -23,6 +23,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertEquals; @@ -96,12 +98,19 @@ public class VcnManagerTest extends VcnTestBase { @Before public void setUp() throws Exception { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); + + getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); } @After public void tearDown() throws Exception { - if (mTestNetworkWrapper != null) { - mTestNetworkWrapper.close(); + try { + if (mTestNetworkWrapper != null) { + mTestNetworkWrapper.close(); + mTestNetworkWrapper = null; + } + } finally { + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } } @@ -172,6 +181,9 @@ public class VcnManagerTest extends VcnTestBase { @Test(expected = SecurityException.class) public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() throws Exception { + // Drop shell permission identity to test unpermissioned behavior. + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + final TestVcnNetworkPolicyChangeListener listener = new TestVcnNetworkPolicyChangeListener(); @@ -192,6 +204,9 @@ public class VcnManagerTest extends VcnTestBase { @Test(expected = SecurityException.class) public void testApplyVcnNetworkPolicy_noNetworkFactoryPermission() throws Exception { + // Drop shell permission identity to test unpermissioned behavior. + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + final NetworkCapabilities nc = new NetworkCapabilities.Builder().build(); final LinkProperties lp = new LinkProperties(); @@ -334,7 +349,7 @@ public class VcnManagerTest extends VcnTestBase { true /* expectNotVcnManaged */, false /* expectNotMetered */); - CarrierPrivilegeUtils.withCarrierPrivileges(mContext, subId, () -> { + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); From 87bae080fc71925f0199e00309d3ea31096ede27 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Thu, 17 Jun 2021 13:53:35 -0700 Subject: [PATCH 0243/1057] Update Mobile Data State on subscription changes. This CL ensures that Vcn instances refresh their mobile data state when they receive a new TelephonySubscriptionSnapshot. A new snapshot may contain different subId -> subGroup mappings, which can affect whether a Vcn instance's subGroup has mobile data enabled or not. This in turn can change which VcnGatewayConnections are brought up by the Vcn. Bug: 191394092 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Ib59b4ed7900a177b17ed4a6e197e271b10937f65 --- .../src/com/android/server/vcn/Vcn.java | 4 ++++ .../java/com/android/server/vcn/VcnTest.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f7d61367c8..95a06fcff7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -453,6 +453,10 @@ public class Vcn extends Handler { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + + // Update the mobile data state after updating the subscription snapshot as a change in + // subIds for a subGroup may affect the mobile data state. + handleMobileDataToggled(); } private void handleMobileDataToggled() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index f681ee19ab..5d2f9d7485 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -242,6 +242,27 @@ public class VcnTest { verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataState() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); + + // Expect mobile data enabled from setUp() + assertTrue(mVcn.isMobileDataEnabled()); + + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(TEST_SUB_IDS_IN_GROUP) + .when(updatedSnapshot) + .getAllSubIdsInGroup(eq(TEST_SUB_GROUP)); + doReturn(false).when(mTelephonyManager).isDataEnabled(); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + assertFalse(mVcn.isMobileDataEnabled()); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); From 149879ce33f11fe6d5ac1dd9f6657aad4fa1bd93 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 18 Jun 2021 02:18:22 +0000 Subject: [PATCH 0244/1057] Update Mobile Data State on subscription changes. This CL ensures that Vcn instances refresh their mobile data state when they receive a new TelephonySubscriptionSnapshot. A new snapshot may contain different subId -> subGroup mappings, which can affect whether a Vcn instance's subGroup has mobile data enabled or not. This in turn can change which VcnGatewayConnections are brought up by the Vcn. Bug: 191394092 Test: atest FrameworksVcnTests CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1740514 Merged-In: Ib59b4ed7900a177b17ed4a6e197e271b10937f65 Change-Id: Ib59b4ed7900a177b17ed4a6e197e271b10937f65 --- .../src/com/android/server/vcn/Vcn.java | 4 ++++ .../java/com/android/server/vcn/VcnTest.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f7d61367c8..95a06fcff7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -453,6 +453,10 @@ public class Vcn extends Handler { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + + // Update the mobile data state after updating the subscription snapshot as a change in + // subIds for a subGroup may affect the mobile data state. + handleMobileDataToggled(); } private void handleMobileDataToggled() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index f681ee19ab..5d2f9d7485 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -242,6 +242,27 @@ public class VcnTest { verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataState() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); + + // Expect mobile data enabled from setUp() + assertTrue(mVcn.isMobileDataEnabled()); + + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(TEST_SUB_IDS_IN_GROUP) + .when(updatedSnapshot) + .getAllSubIdsInGroup(eq(TEST_SUB_GROUP)); + doReturn(false).when(mTelephonyManager).isDataEnabled(); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + assertFalse(mVcn.isMobileDataEnabled()); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); From 34e9758d5aba744c9d90c84ca7137baad55a2750 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 21 Jun 2021 14:57:38 -0700 Subject: [PATCH 0245/1057] Include IkeTunnelConnectionParams in #hashCode and #equals This commit includes IkeTunnelConnectionParams in VcnGatewayConnectionConfig#hashCode and VcnGatewayConnectionConfig#equals. This commit fixes the issue that VcnGatewayConnection was not being restarted as expected. Bug: 191317512 Test: atest FrameworksVcnTests (new tests added) Test: atest CtsVcnTestCases Change-Id: I70182f9b645e55eced1e0a048a1bd87778c1c0f6 --- .../net/vcn/VcnGatewayConnectionConfig.java | 2 + .../vcn/VcnGatewayConnectionConfigTest.java | 64 +++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index d59ad6f888..63e8369655 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -347,6 +347,7 @@ public final class VcnGatewayConnectionConfig { public int hashCode() { return Objects.hash( mGatewayConnectionName, + mTunnelConnectionParams, mExposedCapabilities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); @@ -360,6 +361,7 @@ public final class VcnGatewayConnectionConfig { final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) + && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) && mExposedCapabilities.equals(rhs.mExposedCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 4ce78aa4d8..dc338ae0fd 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -20,6 +20,8 @@ import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -70,6 +72,14 @@ public class VcnGatewayConnectionConfigTest { public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; private static int sGatewayConnectionConfigCount = 0; + private static VcnGatewayConnectionConfig buildTestConfig( + String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) { + return buildTestConfigWithExposedCaps( + new VcnGatewayConnectionConfig.Builder( + gatewayConnectionName, tunnelConnectionParams), + EXPOSED_CAPS); + } + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { return buildTestConfigWithExposedCaps(EXPOSED_CAPS); @@ -83,10 +93,9 @@ public class VcnGatewayConnectionConfigTest { TUNNEL_CONNECTION_PARAMS); } - // Public for use in VcnGatewayConnectionTest - public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { - final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps( + VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) { + builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -95,6 +104,11 @@ public class VcnGatewayConnectionConfigTest { return builder.build(); } + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { + return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps); + } + @Test public void testBuilderRequiresNonNullGatewayConnectionName() { try { @@ -193,4 +207,46 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } + + private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) { + final IkeSessionParams ikeParams = + IkeSessionParamsUtilsTest.createBuilderMinimum() + .setAuthPsk(ikePsk.getBytes()) + .build(); + return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams); + } + + @Test + public void testTunnelConnectionParamsEquals() throws Exception { + final String connectionName = "testTunnelConnectionParamsEquals.connectionName"; + final String psk = "testTunnelConnectionParamsEquals.psk"; + + final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk); + final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams); + + final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk); + final VcnGatewayConnectionConfig anotherConfig = + buildTestConfig(connectionName, anotherTunnelParams); + + assertNotSame(tunnelParams, anotherTunnelParams); + assertEquals(tunnelParams, anotherTunnelParams); + assertEquals(config, anotherConfig); + } + + @Test + public void testTunnelConnectionParamsNotEquals() throws Exception { + final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName"; + + final IkeTunnelConnectionParams tunnelParams = + buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA"); + final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams); + + final IkeTunnelConnectionParams anotherTunnelParams = + buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB"); + final VcnGatewayConnectionConfig anotherConfig = + buildTestConfig(connectionName, anotherTunnelParams); + + assertNotEquals(tunnelParams, anotherTunnelParams); + assertNotEquals(config, anotherConfig); + } } From d069acfe2676f809909ecf6ce6350e1609f81f4d Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 7 May 2021 12:39:09 -0700 Subject: [PATCH 0246/1057] CTS test VCN start on test network. This CL adds CTS testing to verify that VCNs can start on a Test Network. This requires setting up an IKE Session on the Test Network and verifying that a new cell Network comes up. Bug: 182291467 Test: atest CtsVcnTestCases Change-Id: I6f890161b05ae12fb585765f3c42f99e4da47557 --- Vcn/tests/cts/Android.bp | 1 + .../net/vcn/cts/TestNetworkWrapper.java | 29 +++++ .../cts/VcnGatewayConnectionConfigTest.java | 4 +- .../android/net/vcn/cts/VcnManagerTest.java | 114 +++++++++++++++++- .../src/android/net/vcn/cts/VcnTestBase.java | 25 ++-- 5 files changed, 157 insertions(+), 16 deletions(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 3aed5d72ce..59f15f0f6a 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -36,6 +36,7 @@ android_test { "compatibility-device-util-axt", "cts-net-utils", "ctstestrunner-axt", + "ike-tun-utils", "net-tests-utils", "telephony-cts-utils", ], diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 52b6245a18..314750d561 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -20,6 +20,7 @@ import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import android.annotation.NonNull; import android.content.Context; +import android.ipsec.ike.cts.IkeTunUtils; import android.net.ConnectivityManager; import android.net.IpPrefix; import android.net.LinkAddress; @@ -92,6 +93,7 @@ public class TestNetworkWrapper implements AutoCloseable { public final VcnTestNetworkCallback vcnNetworkCallback; public final ParcelFileDescriptor tunFd; + public final IkeTunUtils ikeTunUtils; public final Network tunNetwork; public TestNetworkWrapper( @@ -138,8 +140,10 @@ public class TestNetworkWrapper implements AutoCloseable { mTestNetworkAgent.markConnected(); tunNetwork = vcnNetworkCallback.waitForAvailable(); + ikeTunUtils = new IkeTunUtils(tunFd); mCloseGuard.open(TAG); } catch (Exception e) { + Log.e(TAG, "Failed to bring up TestNetworkWrapper", e); close(); throw e; } @@ -153,6 +157,9 @@ public class TestNetworkWrapper implements AutoCloseable { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA) .setNetworkSpecifier(new TestNetworkSpecifier(iface)) .setSubscriptionIds(subIds); if (!isMetered) { @@ -346,13 +353,35 @@ public class TestNetworkWrapper implements AutoCloseable { /** NetworkCallback to used for tracking test network events. */ // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities public static class VcnTestNetworkCallback extends TestNetworkCallback { + private final BlockingQueue mAvailableHistory = new LinkedBlockingQueue<>(); + private final BlockingQueue mLostHistory = new LinkedBlockingQueue<>(); private final BlockingQueue mCapabilitiesChangedHistory = new LinkedBlockingQueue<>(); + @Override + public Network waitForAvailable() throws InterruptedException { + return mAvailableHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public Network waitForLost() throws InterruptedException { + return mLostHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); } + @Override + public void onAvailable(@NonNull Network network) { + mAvailableHistory.offer(network); + } + + @Override + public void onLost(@NonNull Network network) { + mLostHistory.offer(network); + } + @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities nc) { diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 20bdc0accd..4cc6335a34 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -46,7 +46,7 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { }; private static final int MAX_MTU = 1360; - private static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { + public static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { return new VcnGatewayConnectionConfig.Builder( VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams()) .addExposedCapability(NET_CAPABILITY_INTERNET) @@ -54,7 +54,7 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { .setMaxMtu(MAX_MTU); } - public static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { + private static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { return buildVcnGatewayConnectionConfigBase().build(); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 7fec0011b0..06c77d5cf7 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -37,12 +37,16 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.ipsec.ike.cts.IkeTunUtils; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; import android.os.SystemClock; @@ -79,6 +83,9 @@ public class VcnManagerTest extends VcnTestBase { private static final Inet6Address LOCAL_V6_ADDRESS = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private static final long IKE_DETERMINISTIC_INITIATOR_SPI = + Long.parseLong("46B8ECA1E0D72A18", 16); + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; @@ -114,11 +121,22 @@ public class VcnManagerTest extends VcnTestBase { } } - private VcnConfig buildVcnConfig() { + private VcnConfig.Builder buildVcnConfigBase() { + // TODO(b/191371669): remove the exposed MMS capability and use + // VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig() instead return new VcnConfig.Builder(mContext) .addGatewayConnectionConfig( - VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig()) - .build(); + VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase() + .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .build()); + } + + private VcnConfig buildVcnConfig() { + return buildVcnConfigBase().build(); + } + + private VcnConfig buildTestModeVcnConfig() { + return buildVcnConfigBase().setIsTestModeProfile().build(); } private int verifyAndGetValidDataSubId() { @@ -396,4 +414,94 @@ public class VcnManagerTest extends VcnTestBase { + " NOT_METERED=" + expectNotMetered); } + + @Test + public void testSetVcnConfigOnTestNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + + // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for + // VCN network + final Network lostCellNetwork = cellNetworkCb.waitForLost(); + assertEquals(cellNetwork, lostCellNetwork); + + injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); + + final Network vcnNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("VCN network did not come up", vcnNetwork); + + mVcnManager.clearVcnConfig(subGrp); + + // Expect VCN Network to disappear after VcnConfig is cleared + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } + + private void injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) + throws Exception { + // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and + // capturing IKE packets with a live server. + final String ikeInitResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52120222000000000000001d022000030" + + "0000002c010100040300000c0100000c800e0080030000080300000803000008" + + "02000008000000080400000e28000108000e0000164d3413d855a1642d4d6355" + + "a8ef6666bfaa28a4b5264600c9ffbaef7930bd33af49022926013aae0a48d764" + + "750ccb3987605957e31a2ef0e6838cfa67af989933c2879434081c4e9787f0d4" + + "4da0d7dacca5589702a4537ee4fb18e8db21a948b245260f55212a1c619f61c6" + + "fa1caaff4474082f9714b14ef4bcc7b2b8f43fcb939931119e53b05274faec65" + + "2816c563529e60c1a88183eba9c456ecb644faf57b726b83e3242e08489d95e9" + + "81e59c7ad82cf3cdfb00fe0213c4e65d61e88bbefbd536261027da722a2bbf89" + + "c6378e63ce6fbcef282421e5576bba1b2faa3c4c2d41028f91df7ba165a24a18" + + "fcba4f96db3e5e0eed76dc7c3c432362dd4a82d32900002461cbd03c08819730" + + "f1060ed0c0446f784eb8dd884d3f73f54eb2b0c3071cc4f32900001c00004004" + + "07150f3fd9584dbebb7e88ad256c7bfb9b0bb55a2900001c00004005e3aa3788" + + "7040e38dbb4de8fd435161cce904ec59290000080000402e290000100000402f" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e20232000000001000000fc240000e0" + + "1a666eb2a02b37682436a18fff5e9cef67b9096d6c7887ed235f8b5173c9469e" + + "361621b66849de2dbcabf956b3d055cafafd503530543540e81dac9bf8fb8826" + + "e08bc99e9ed2185d8f1322c8885abe4f98a9832c694da775eaa4ae69f17b8cbf" + + "b009bf82b4bf4012bca489595631c3168cd417f813e7d177d2ceb70766a0773c" + + "8819d8763627ddc9455ae3d5a5a03224020a66c8e58c8073c4a1fcf5d67cfa95" + + "15de86b392a63ff54ff5572302b9ce7725085b05839252794c3680f5d8f34019" + + "fa1930ea045d2a9987850e2049235c7328ef148370b6a3403408b987"; + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + false /* expectedUseEncap */, + ikeInitResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthResp); + } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index 7ed201eb0a..4b79fa9248 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -18,15 +18,17 @@ package android.net.vcn.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; -import android.net.ipsec.ike.SaProposal; import android.net.ipsec.ike.TunnelModeChildSessionParams; public class VcnTestBase { @@ -39,9 +41,10 @@ public class VcnTestBase { IkeSessionParams ikeParams) { final ChildSaProposal childProposal = new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) .build(); + final TunnelModeChildSessionParams childParams = new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); @@ -51,16 +54,16 @@ public class VcnTestBase { protected static IkeSessionParams.Builder getIkeSessionParamsBase() { final IkeSaProposal ikeProposal = new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96) + .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC) .addDhGroup(DH_GROUP_2048_BIT_MODP) - .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) .build(); final String serverHostname = "2001:db8:1::100"; - final String testLocalId = "test.client.com"; - final String testRemoteId = "test.server.com"; - final byte[] psk = "psk".getBytes(); + final String testLocalId = "client.test.ike.android.net"; + final String testRemoteId = "server.test.ike.android.net"; + final byte[] psk = "ikeAndroidPsk".getBytes(); return new IkeSessionParams.Builder() .setServerHostname(serverHostname) From 6536ce56739b8407eabfee137f692780e12be915 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 9 Jun 2021 11:22:30 -0700 Subject: [PATCH 0247/1057] CTS Test VCN network migration. This CL adds CTS testing for VCN Network bringup and network migration. The test first brings up a VCN on a test network, then kills the test network and brings up a second test network. Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: I05e288386d387c7ff40c3c5b73485c61603a558e --- .../android/net/vcn/cts/VcnManagerTest.java | 147 ++++++++++++++++-- 1 file changed, 131 insertions(+), 16 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 06c77d5cf7..e6de5544f5 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -82,6 +82,8 @@ public class VcnManagerTest extends VcnTestBase { private static final Inet6Address LOCAL_V6_ADDRESS = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private static final Inet6Address SECONDARY_LOCAL_V6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::3"); private static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); @@ -439,29 +441,35 @@ public class VcnManagerTest extends VcnTestBase { CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for - // VCN network - final Network lostCellNetwork = cellNetworkCb.waitForLost(); - assertEquals(cellNetwork, lostCellNetwork); - - injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); - - final Network vcnNetwork = cellNetworkCb.waitForAvailable(); - assertNotNull("VCN network did not come up", vcnNetwork); - - mVcnManager.clearVcnConfig(subGrp); - - // Expect VCN Network to disappear after VcnConfig is cleared - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); }); }); mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); } + private Network setupAndGetVcnNetwork( + @NonNull ParcelUuid subGrp, + @NonNull Network cellNetwork, + @NonNull VcnTestNetworkCallback cellNetworkCb) + throws Exception { + mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + + // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for + // VCN network + final Network lostCellNetwork = cellNetworkCb.waitForLost(); + assertEquals(cellNetwork, lostCellNetwork); + + injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); + + final Network vcnNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("VCN network did not come up", vcnNetwork); + return vcnNetwork; + } + private void injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) throws Exception { // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and @@ -504,4 +512,111 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */, ikeAuthResp); } + + private void clearVcnConfigsAndVerifyNetworkTeardown( + @NonNull ParcelUuid subGrp, + @NonNull VcnTestNetworkCallback cellNetworkCb, + @NonNull Network vcnNetwork) + throws Exception { + mVcnManager.clearVcnConfig(subGrp); + + // Expect VCN Network to disappear after VcnConfig is cleared + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + } + + @Test + public void testVcnMigrationAfterNetworkDies() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + + mTestNetworkWrapper.close(); + mTestNetworkWrapper.vcnNetworkCallback.waitForLost(); + + final TestNetworkWrapper secondaryTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + SECONDARY_LOCAL_V6_ADDRESS); + + try { + assertNotNull("No test network found", secondaryTestNetworkWrapper.tunNetwork); + + injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + } finally { + secondaryTestNetworkWrapper.close(); + } + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } + + private void injectAndVerifyIkeMobikePackets(@NonNull IkeTunUtils ikeTunUtils) + throws Exception { + // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and + // capturing IKE packets with a live server. To force the mobility event, use + // IkeSession#setNetwork with the new desired Network. + final String ikeUpdateSaResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000020000007c29000060" + + "a1fd35f112d92d1df19ce734f6edf56ccda1bfd44ef6de428a097e04d5b40b28" + + "3897e42f23dd53e444dc6c676cf9a7d9d73bb3975d663ec351fb5ae4e56a55d8" + + "cbcf376a3b99cc6fd858621cc78b3017d895e4309f09a444028dba85"; + final String ikeCreateChildResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e20242000000003000000cc210000b0" + + "e6bb78203dbe2189806c5cecef5040b8c4c0253895c7c0acea6483a1f0f72425" + + "77ab46e18d553329d4ae1bd31cf57eec6ec31ceb1f2ed6b1195cac98b4b97a25" + + "115d14c414e44dba8ebbdaf502e43f98a09036bee0ea2a621176300874a3eae8" + + "c988357255b4e5923928d335b0ef62a565333fae6a64c85ac30e7da34ceeade4" + + "1a161bcad0b51f8209ee1fdaf53d50359ad6b986ecd4290c9f69a34c64ddc0eb" + + "73b8f3231f3f4e057404c18d"; + final String ikeDeleteChildResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000040000004c2a000030" + + "53d97806d48ce44e0d4e1adf1de36778f77c3823bfaf8186cc71d4dc73497099" + + "a9049e7be8a2013affd56ab7"; + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 2 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeUpdateSaResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 3 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeCreateChildResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 4 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeDeleteChildResp); + } } From 41c5861475cf23b7f6c31bdcf28cf3f4e27e7868 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 21 Jun 2021 12:06:56 -0700 Subject: [PATCH 0248/1057] CTS test VCN entering safemode. This CL adds CTS testing for verying that a VCN instance will enter safemode if the device is not able to establish a and validate a VcnGatewayConnection by the system-specificed timeout. Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: I39d04ad63cd6ff00d601d6871b3230a113cfde65 --- .../net/vcn/cts/TestNetworkWrapper.java | 7 +- .../android/net/vcn/cts/VcnManagerTest.java | 69 ++++++++++++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 314750d561..d70cc2b168 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -369,7 +369,12 @@ public class TestNetworkWrapper implements AutoCloseable { } public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { - return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return waitForOnCapabilitiesChanged(NETWORK_CB_TIMEOUT_MS); + } + + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged(long timeoutMillis) + throws Exception { + return mCapabilitiesChangedHistory.poll(timeoutMillis, TimeUnit.MILLISECONDS); } @Override diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e6de5544f5..2572593c6c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -75,6 +75,7 @@ public class VcnManagerTest extends VcnTestBase { private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; + private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35); private static final Executor INLINE_EXECUTOR = Runnable::run; @@ -391,12 +392,20 @@ public class VcnManagerTest extends VcnTestBase { private void verifyExpectedUnderlyingNetworkCapabilities( boolean expectNotVcnManaged, boolean expectNotMetered) throws Exception { + verifyExpectedUnderlyingNetworkCapabilities( + expectNotVcnManaged, expectNotMetered, TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + } + + private void verifyExpectedUnderlyingNetworkCapabilities( + boolean expectNotVcnManaged, boolean expectNotMetered, long timeoutMillis) + throws Exception { final long start = SystemClock.elapsedRealtime(); // Wait for NetworkCapabilities changes until they match the expected capabilities do { final CapabilitiesChangedEvent capabilitiesChangedEvent = - mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged(); + mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged( + timeoutMillis); assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent); final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities; @@ -406,7 +415,7 @@ public class VcnManagerTest extends VcnTestBase { && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) { return; } - } while (SystemClock.elapsedRealtime() - start < TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + } while (SystemClock.elapsedRealtime() - start < timeoutMillis); fail( "Expected update for network=" @@ -619,4 +628,60 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */, ikeDeleteChildResp); } + + @Test + public void testVcnSafemodeOnTestNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, false /* expectNotMetered */); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + + // TODO(b/191801185): use VcnStatusCallbacks to verify safemode + + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + false /* expectNotVcnManaged */, + false /* expectNotMetered */); + + // After VCN has started up, wait for safemode to kick in and expect the underlying + // Test Network to regain NOT_VCN_MANAGED. + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + SAFEMODE_TIMEOUT_MILLIS); + + // Verify that VCN Network is also lost in safemode + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + + mVcnManager.clearVcnConfig(subGrp); + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } } From 739fe3abc6be35e35c251d79c699e93f8a8736fd Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 23 Jun 2021 02:18:09 +0000 Subject: [PATCH 0249/1057] Include IkeTunnelConnectionParams in #hashCode and #equals This commit includes IkeTunnelConnectionParams in VcnGatewayConnectionConfig#hashCode and VcnGatewayConnectionConfig#equals. This commit fixes the issue that VcnGatewayConnection was not being restarted as expected. Bug: 191317512 Test: atest FrameworksVcnTests (new tests added) Test: atest CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1742657 Merged-In: I70182f9b645e55eced1e0a048a1bd87778c1c0f6 Change-Id: I70182f9b645e55eced1e0a048a1bd87778c1c0f6 --- .../net/vcn/VcnGatewayConnectionConfig.java | 2 + .../vcn/VcnGatewayConnectionConfigTest.java | 64 +++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 86cd23d1e9..752ef3e39a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -352,6 +352,7 @@ public final class VcnGatewayConnectionConfig { public int hashCode() { return Objects.hash( mGatewayConnectionName, + mTunnelConnectionParams, mExposedCapabilities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); @@ -365,6 +366,7 @@ public final class VcnGatewayConnectionConfig { final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) + && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) && mExposedCapabilities.equals(rhs.mExposedCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 4ce78aa4d8..dc338ae0fd 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -20,6 +20,8 @@ import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -70,6 +72,14 @@ public class VcnGatewayConnectionConfigTest { public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; private static int sGatewayConnectionConfigCount = 0; + private static VcnGatewayConnectionConfig buildTestConfig( + String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) { + return buildTestConfigWithExposedCaps( + new VcnGatewayConnectionConfig.Builder( + gatewayConnectionName, tunnelConnectionParams), + EXPOSED_CAPS); + } + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { return buildTestConfigWithExposedCaps(EXPOSED_CAPS); @@ -83,10 +93,9 @@ public class VcnGatewayConnectionConfigTest { TUNNEL_CONNECTION_PARAMS); } - // Public for use in VcnGatewayConnectionTest - public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { - final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps( + VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) { + builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -95,6 +104,11 @@ public class VcnGatewayConnectionConfigTest { return builder.build(); } + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { + return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps); + } + @Test public void testBuilderRequiresNonNullGatewayConnectionName() { try { @@ -193,4 +207,46 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } + + private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) { + final IkeSessionParams ikeParams = + IkeSessionParamsUtilsTest.createBuilderMinimum() + .setAuthPsk(ikePsk.getBytes()) + .build(); + return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams); + } + + @Test + public void testTunnelConnectionParamsEquals() throws Exception { + final String connectionName = "testTunnelConnectionParamsEquals.connectionName"; + final String psk = "testTunnelConnectionParamsEquals.psk"; + + final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk); + final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams); + + final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk); + final VcnGatewayConnectionConfig anotherConfig = + buildTestConfig(connectionName, anotherTunnelParams); + + assertNotSame(tunnelParams, anotherTunnelParams); + assertEquals(tunnelParams, anotherTunnelParams); + assertEquals(config, anotherConfig); + } + + @Test + public void testTunnelConnectionParamsNotEquals() throws Exception { + final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName"; + + final IkeTunnelConnectionParams tunnelParams = + buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA"); + final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams); + + final IkeTunnelConnectionParams anotherTunnelParams = + buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB"); + final VcnGatewayConnectionConfig anotherConfig = + buildTestConfig(connectionName, anotherTunnelParams); + + assertNotEquals(tunnelParams, anotherTunnelParams); + assertNotEquals(config, anotherConfig); + } } From 7e77e727f95561cdc8115eb4736af5de679d3817 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Fri, 7 May 2021 12:39:09 -0700 Subject: [PATCH 0250/1057] CTS test VCN start on test network. This CL adds CTS testing to verify that VCNs can start on a Test Network. This requires setting up an IKE Session on the Test Network and verifying that a new cell Network comes up. Bug: 182291467 Test: atest CtsVcnTestCases Change-Id: I6f890161b05ae12fb585765f3c42f99e4da47557 Merged-In: I6f890161b05ae12fb585765f3c42f99e4da47557 --- Vcn/tests/cts/Android.bp | 1 + .../net/vcn/cts/TestNetworkWrapper.java | 29 +++++ .../cts/VcnGatewayConnectionConfigTest.java | 4 +- .../android/net/vcn/cts/VcnManagerTest.java | 114 +++++++++++++++++- .../src/android/net/vcn/cts/VcnTestBase.java | 25 ++-- 5 files changed, 157 insertions(+), 16 deletions(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 3aed5d72ce..59f15f0f6a 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -36,6 +36,7 @@ android_test { "compatibility-device-util-axt", "cts-net-utils", "ctstestrunner-axt", + "ike-tun-utils", "net-tests-utils", "telephony-cts-utils", ], diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 52b6245a18..314750d561 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -20,6 +20,7 @@ import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import android.annotation.NonNull; import android.content.Context; +import android.ipsec.ike.cts.IkeTunUtils; import android.net.ConnectivityManager; import android.net.IpPrefix; import android.net.LinkAddress; @@ -92,6 +93,7 @@ public class TestNetworkWrapper implements AutoCloseable { public final VcnTestNetworkCallback vcnNetworkCallback; public final ParcelFileDescriptor tunFd; + public final IkeTunUtils ikeTunUtils; public final Network tunNetwork; public TestNetworkWrapper( @@ -138,8 +140,10 @@ public class TestNetworkWrapper implements AutoCloseable { mTestNetworkAgent.markConnected(); tunNetwork = vcnNetworkCallback.waitForAvailable(); + ikeTunUtils = new IkeTunUtils(tunFd); mCloseGuard.open(TAG); } catch (Exception e) { + Log.e(TAG, "Failed to bring up TestNetworkWrapper", e); close(); throw e; } @@ -153,6 +157,9 @@ public class TestNetworkWrapper implements AutoCloseable { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA) .setNetworkSpecifier(new TestNetworkSpecifier(iface)) .setSubscriptionIds(subIds); if (!isMetered) { @@ -346,13 +353,35 @@ public class TestNetworkWrapper implements AutoCloseable { /** NetworkCallback to used for tracking test network events. */ // TODO(b/187231331): remove once TestNetworkCallback supports tracking NetworkCapabilities public static class VcnTestNetworkCallback extends TestNetworkCallback { + private final BlockingQueue mAvailableHistory = new LinkedBlockingQueue<>(); + private final BlockingQueue mLostHistory = new LinkedBlockingQueue<>(); private final BlockingQueue mCapabilitiesChangedHistory = new LinkedBlockingQueue<>(); + @Override + public Network waitForAvailable() throws InterruptedException { + return mAvailableHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public Network waitForLost() throws InterruptedException { + return mLostHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); } + @Override + public void onAvailable(@NonNull Network network) { + mAvailableHistory.offer(network); + } + + @Override + public void onLost(@NonNull Network network) { + mLostHistory.offer(network); + } + @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities nc) { diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 20bdc0accd..4cc6335a34 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -46,7 +46,7 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { }; private static final int MAX_MTU = 1360; - private static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { + public static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { return new VcnGatewayConnectionConfig.Builder( VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams()) .addExposedCapability(NET_CAPABILITY_INTERNET) @@ -54,7 +54,7 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { .setMaxMtu(MAX_MTU); } - public static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { + private static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { return buildVcnGatewayConnectionConfigBase().build(); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 7fec0011b0..06c77d5cf7 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -37,12 +37,16 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.ipsec.ike.cts.IkeTunUtils; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; import android.os.SystemClock; @@ -79,6 +83,9 @@ public class VcnManagerTest extends VcnTestBase { private static final Inet6Address LOCAL_V6_ADDRESS = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private static final long IKE_DETERMINISTIC_INITIATOR_SPI = + Long.parseLong("46B8ECA1E0D72A18", 16); + private final Context mContext; private final VcnManager mVcnManager; private final SubscriptionManager mSubscriptionManager; @@ -114,11 +121,22 @@ public class VcnManagerTest extends VcnTestBase { } } - private VcnConfig buildVcnConfig() { + private VcnConfig.Builder buildVcnConfigBase() { + // TODO(b/191371669): remove the exposed MMS capability and use + // VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig() instead return new VcnConfig.Builder(mContext) .addGatewayConnectionConfig( - VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig()) - .build(); + VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase() + .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .build()); + } + + private VcnConfig buildVcnConfig() { + return buildVcnConfigBase().build(); + } + + private VcnConfig buildTestModeVcnConfig() { + return buildVcnConfigBase().setIsTestModeProfile().build(); } private int verifyAndGetValidDataSubId() { @@ -396,4 +414,94 @@ public class VcnManagerTest extends VcnTestBase { + " NOT_METERED=" + expectNotMetered); } + + @Test + public void testSetVcnConfigOnTestNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + + // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for + // VCN network + final Network lostCellNetwork = cellNetworkCb.waitForLost(); + assertEquals(cellNetwork, lostCellNetwork); + + injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); + + final Network vcnNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("VCN network did not come up", vcnNetwork); + + mVcnManager.clearVcnConfig(subGrp); + + // Expect VCN Network to disappear after VcnConfig is cleared + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } + + private void injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) + throws Exception { + // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and + // capturing IKE packets with a live server. + final String ikeInitResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52120222000000000000001d022000030" + + "0000002c010100040300000c0100000c800e0080030000080300000803000008" + + "02000008000000080400000e28000108000e0000164d3413d855a1642d4d6355" + + "a8ef6666bfaa28a4b5264600c9ffbaef7930bd33af49022926013aae0a48d764" + + "750ccb3987605957e31a2ef0e6838cfa67af989933c2879434081c4e9787f0d4" + + "4da0d7dacca5589702a4537ee4fb18e8db21a948b245260f55212a1c619f61c6" + + "fa1caaff4474082f9714b14ef4bcc7b2b8f43fcb939931119e53b05274faec65" + + "2816c563529e60c1a88183eba9c456ecb644faf57b726b83e3242e08489d95e9" + + "81e59c7ad82cf3cdfb00fe0213c4e65d61e88bbefbd536261027da722a2bbf89" + + "c6378e63ce6fbcef282421e5576bba1b2faa3c4c2d41028f91df7ba165a24a18" + + "fcba4f96db3e5e0eed76dc7c3c432362dd4a82d32900002461cbd03c08819730" + + "f1060ed0c0446f784eb8dd884d3f73f54eb2b0c3071cc4f32900001c00004004" + + "07150f3fd9584dbebb7e88ad256c7bfb9b0bb55a2900001c00004005e3aa3788" + + "7040e38dbb4de8fd435161cce904ec59290000080000402e290000100000402f" + + "00020003000400050000000800004014"; + final String ikeAuthResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e20232000000001000000fc240000e0" + + "1a666eb2a02b37682436a18fff5e9cef67b9096d6c7887ed235f8b5173c9469e" + + "361621b66849de2dbcabf956b3d055cafafd503530543540e81dac9bf8fb8826" + + "e08bc99e9ed2185d8f1322c8885abe4f98a9832c694da775eaa4ae69f17b8cbf" + + "b009bf82b4bf4012bca489595631c3168cd417f813e7d177d2ceb70766a0773c" + + "8819d8763627ddc9455ae3d5a5a03224020a66c8e58c8073c4a1fcf5d67cfa95" + + "15de86b392a63ff54ff5572302b9ce7725085b05839252794c3680f5d8f34019" + + "fa1930ea045d2a9987850e2049235c7328ef148370b6a3403408b987"; + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + false /* expectedUseEncap */, + ikeInitResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthResp); + } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index 7ed201eb0a..4b79fa9248 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -18,15 +18,17 @@ package android.net.vcn.cts; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; -import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; -import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; +import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96; +import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; +import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; -import android.net.ipsec.ike.SaProposal; import android.net.ipsec.ike.TunnelModeChildSessionParams; public class VcnTestBase { @@ -39,9 +41,10 @@ public class VcnTestBase { IkeSessionParams ikeParams) { final ChildSaProposal childProposal = new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) .build(); + final TunnelModeChildSessionParams childParams = new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build(); @@ -51,16 +54,16 @@ public class VcnTestBase { protected static IkeSessionParams.Builder getIkeSessionParamsBase() { final IkeSaProposal ikeProposal = new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96) + .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC) .addDhGroup(DH_GROUP_2048_BIT_MODP) - .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC) .build(); final String serverHostname = "2001:db8:1::100"; - final String testLocalId = "test.client.com"; - final String testRemoteId = "test.server.com"; - final byte[] psk = "psk".getBytes(); + final String testLocalId = "client.test.ike.android.net"; + final String testRemoteId = "server.test.ike.android.net"; + final byte[] psk = "ikeAndroidPsk".getBytes(); return new IkeSessionParams.Builder() .setServerHostname(serverHostname) From a071f7cdbd2eb574c9bbeebf39630f5581400e44 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 9 Jun 2021 11:22:30 -0700 Subject: [PATCH 0251/1057] CTS Test VCN network migration. This CL adds CTS testing for VCN Network bringup and network migration. The test first brings up a VCN on a test network, then kills the test network and brings up a second test network. Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: I05e288386d387c7ff40c3c5b73485c61603a558e Merged-In: I05e288386d387c7ff40c3c5b73485c61603a558e --- .../android/net/vcn/cts/VcnManagerTest.java | 147 ++++++++++++++++-- 1 file changed, 131 insertions(+), 16 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 06c77d5cf7..e6de5544f5 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -82,6 +82,8 @@ public class VcnManagerTest extends VcnTestBase { private static final Inet6Address LOCAL_V6_ADDRESS = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private static final Inet6Address SECONDARY_LOCAL_V6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::3"); private static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); @@ -439,29 +441,35 @@ public class VcnManagerTest extends VcnTestBase { CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for - // VCN network - final Network lostCellNetwork = cellNetworkCb.waitForLost(); - assertEquals(cellNetwork, lostCellNetwork); - - injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); - - final Network vcnNetwork = cellNetworkCb.waitForAvailable(); - assertNotNull("VCN network did not come up", vcnNetwork); - - mVcnManager.clearVcnConfig(subGrp); - - // Expect VCN Network to disappear after VcnConfig is cleared - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); }); }); mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); } + private Network setupAndGetVcnNetwork( + @NonNull ParcelUuid subGrp, + @NonNull Network cellNetwork, + @NonNull VcnTestNetworkCallback cellNetworkCb) + throws Exception { + mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + + // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for + // VCN network + final Network lostCellNetwork = cellNetworkCb.waitForLost(); + assertEquals(cellNetwork, lostCellNetwork); + + injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); + + final Network vcnNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("VCN network did not come up", vcnNetwork); + return vcnNetwork; + } + private void injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) throws Exception { // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and @@ -504,4 +512,111 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */, ikeAuthResp); } + + private void clearVcnConfigsAndVerifyNetworkTeardown( + @NonNull ParcelUuid subGrp, + @NonNull VcnTestNetworkCallback cellNetworkCb, + @NonNull Network vcnNetwork) + throws Exception { + mVcnManager.clearVcnConfig(subGrp); + + // Expect VCN Network to disappear after VcnConfig is cleared + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + } + + @Test + public void testVcnMigrationAfterNetworkDies() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + + mTestNetworkWrapper.close(); + mTestNetworkWrapper.vcnNetworkCallback.waitForLost(); + + final TestNetworkWrapper secondaryTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + SECONDARY_LOCAL_V6_ADDRESS); + + try { + assertNotNull("No test network found", secondaryTestNetworkWrapper.tunNetwork); + + injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + } finally { + secondaryTestNetworkWrapper.close(); + } + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } + + private void injectAndVerifyIkeMobikePackets(@NonNull IkeTunUtils ikeTunUtils) + throws Exception { + // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and + // capturing IKE packets with a live server. To force the mobility event, use + // IkeSession#setNetwork with the new desired Network. + final String ikeUpdateSaResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000020000007c29000060" + + "a1fd35f112d92d1df19ce734f6edf56ccda1bfd44ef6de428a097e04d5b40b28" + + "3897e42f23dd53e444dc6c676cf9a7d9d73bb3975d663ec351fb5ae4e56a55d8" + + "cbcf376a3b99cc6fd858621cc78b3017d895e4309f09a444028dba85"; + final String ikeCreateChildResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e20242000000003000000cc210000b0" + + "e6bb78203dbe2189806c5cecef5040b8c4c0253895c7c0acea6483a1f0f72425" + + "77ab46e18d553329d4ae1bd31cf57eec6ec31ceb1f2ed6b1195cac98b4b97a25" + + "115d14c414e44dba8ebbdaf502e43f98a09036bee0ea2a621176300874a3eae8" + + "c988357255b4e5923928d335b0ef62a565333fae6a64c85ac30e7da34ceeade4" + + "1a161bcad0b51f8209ee1fdaf53d50359ad6b986ecd4290c9f69a34c64ddc0eb" + + "73b8f3231f3f4e057404c18d"; + final String ikeDeleteChildResp = + "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000040000004c2a000030" + + "53d97806d48ce44e0d4e1adf1de36778f77c3823bfaf8186cc71d4dc73497099" + + "a9049e7be8a2013affd56ab7"; + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 2 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeUpdateSaResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 3 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeCreateChildResp); + + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 4 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeDeleteChildResp); + } } From 0c6683346928ea26b512606655430962d41acfd1 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Mon, 21 Jun 2021 12:06:56 -0700 Subject: [PATCH 0252/1057] CTS test VCN entering safemode. This CL adds CTS testing for verying that a VCN instance will enter safemode if the device is not able to establish a and validate a VcnGatewayConnection by the system-specificed timeout. Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: I39d04ad63cd6ff00d601d6871b3230a113cfde65 Merged-In: I39d04ad63cd6ff00d601d6871b3230a113cfde65 --- .../net/vcn/cts/TestNetworkWrapper.java | 7 +- .../android/net/vcn/cts/VcnManagerTest.java | 69 ++++++++++++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 314750d561..d70cc2b168 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -369,7 +369,12 @@ public class TestNetworkWrapper implements AutoCloseable { } public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { - return mCapabilitiesChangedHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return waitForOnCapabilitiesChanged(NETWORK_CB_TIMEOUT_MS); + } + + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged(long timeoutMillis) + throws Exception { + return mCapabilitiesChangedHistory.poll(timeoutMillis, TimeUnit.MILLISECONDS); } @Override diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e6de5544f5..2572593c6c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -75,6 +75,7 @@ public class VcnManagerTest extends VcnTestBase { private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; + private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35); private static final Executor INLINE_EXECUTOR = Runnable::run; @@ -391,12 +392,20 @@ public class VcnManagerTest extends VcnTestBase { private void verifyExpectedUnderlyingNetworkCapabilities( boolean expectNotVcnManaged, boolean expectNotMetered) throws Exception { + verifyExpectedUnderlyingNetworkCapabilities( + expectNotVcnManaged, expectNotMetered, TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + } + + private void verifyExpectedUnderlyingNetworkCapabilities( + boolean expectNotVcnManaged, boolean expectNotMetered, long timeoutMillis) + throws Exception { final long start = SystemClock.elapsedRealtime(); // Wait for NetworkCapabilities changes until they match the expected capabilities do { final CapabilitiesChangedEvent capabilitiesChangedEvent = - mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged(); + mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged( + timeoutMillis); assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent); final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities; @@ -406,7 +415,7 @@ public class VcnManagerTest extends VcnTestBase { && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) { return; } - } while (SystemClock.elapsedRealtime() - start < TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + } while (SystemClock.elapsedRealtime() - start < timeoutMillis); fail( "Expected update for network=" @@ -619,4 +628,60 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */, ikeDeleteChildResp); } + + @Test + public void testVcnSafemodeOnTestNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + mTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + LOCAL_V6_ADDRESS); + assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, false /* expectNotMetered */); + + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before + // waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + + // TODO(b/191801185): use VcnStatusCallbacks to verify safemode + + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + verifyExpectedUnderlyingNetworkCapabilities( + false /* expectNotVcnManaged */, + false /* expectNotMetered */); + + // After VCN has started up, wait for safemode to kick in and expect the underlying + // Test Network to regain NOT_VCN_MANAGED. + verifyExpectedUnderlyingNetworkCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + SAFEMODE_TIMEOUT_MILLIS); + + // Verify that VCN Network is also lost in safemode + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); + + mVcnManager.clearVcnConfig(subGrp); + }); + }); + + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } } From 3ced1c972999b4e9608fb45258efa5dc9be54767 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 23 Jun 2021 15:35:02 -0700 Subject: [PATCH 0253/1057] Rename NetCaps listener util. This CL renames a utility in VcnManagerTest used to wait for specific NetworkCapabilities changes on a Network. It also removes an overloaded version of the previous method and specifies the timeout for all method calls. Bug: 189125789 Test: atest CtsVcnTestCases Change-Id: Id5fb9656f780f0c0445535b8526e8c7395d957e9 --- .../android/net/vcn/cts/VcnManagerTest.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 2572593c6c..e12d9c00b4 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -366,37 +366,34 @@ public class VcnManagerTest extends VcnTestBase { assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED - verifyExpectedUnderlyingNetworkCapabilities( + waitForExpectedUnderlyingNetworkWithCapabilities( true /* expectNotVcnManaged */, - false /* expectNotMetered */); + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); // Once VCN starts, the test network should lose NOT_VCN_MANAGED - verifyExpectedUnderlyingNetworkCapabilities( + waitForExpectedUnderlyingNetworkWithCapabilities( false /* expectNotVcnManaged */, - false /* expectNotMetered */); + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); mVcnManager.clearVcnConfig(subGrp); // After the VCN tears down, the test network should have // NOT_VCN_MANAGED again - verifyExpectedUnderlyingNetworkCapabilities( + waitForExpectedUnderlyingNetworkWithCapabilities( true /* expectNotVcnManaged */, - false /* expectNotMetered */); + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); }); }); } - private void verifyExpectedUnderlyingNetworkCapabilities( - boolean expectNotVcnManaged, boolean expectNotMetered) throws Exception { - verifyExpectedUnderlyingNetworkCapabilities( - expectNotVcnManaged, expectNotMetered, TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - } - - private void verifyExpectedUnderlyingNetworkCapabilities( + private void waitForExpectedUnderlyingNetworkWithCapabilities( boolean expectNotVcnManaged, boolean expectNotMetered, long timeoutMillis) throws Exception { final long start = SystemClock.elapsedRealtime(); @@ -643,8 +640,10 @@ public class VcnManagerTest extends VcnTestBase { assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED - verifyExpectedUnderlyingNetworkCapabilities( - true /* expectNotVcnManaged */, false /* expectNotMetered */); + waitForExpectedUnderlyingNetworkWithCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. @@ -663,13 +662,14 @@ public class VcnManagerTest extends VcnTestBase { // TODO(b/191801185): use VcnStatusCallbacks to verify safemode // Once VCN starts, the test network should lose NOT_VCN_MANAGED - verifyExpectedUnderlyingNetworkCapabilities( + waitForExpectedUnderlyingNetworkWithCapabilities( false /* expectNotVcnManaged */, - false /* expectNotMetered */); + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); // After VCN has started up, wait for safemode to kick in and expect the underlying // Test Network to regain NOT_VCN_MANAGED. - verifyExpectedUnderlyingNetworkCapabilities( + waitForExpectedUnderlyingNetworkWithCapabilities( true /* expectNotVcnManaged */, false /* expectNotMetered */, SAFEMODE_TIMEOUT_MILLIS); From f45f39404d3416563ea67c72035475836d8013b0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 25 Jun 2021 12:03:10 -0700 Subject: [PATCH 0254/1057] Fix dangling NetworkAgent This change fixes the potential for a networkAgent to be left dangling, due to a situation where a VcnGatewayConnection shuts down, but fails to unregister it's NetworkAgent. The root cause was that the NetworkAgent was not unregistered when moving to the DisconnectedState from the RetryTimeoutState, and the new state assumed that there was no NetworkAgent, and thus failed to close it when disconnecting. Thus, this change ensures that the NetworkAgent is closed before moving to the DisconnectedState. Additionally, it adds safety-checks to onQuitting(), ensuring that if all else fails, these fields are cleaned up. Lastly, this change adds the specific gateway reference to facilitate future debugging of issues such as this where there is potential for duplicate networks, or gateway connections. Bug: 191707296 Test: atest FrameworksVcnTests Change-Id: I84cd43a0c136662f5c2d229650f1f5f889e6f144 --- .../src/com/android/server/vcn/Vcn.java | 6 +++- .../server/vcn/VcnGatewayConnection.java | 16 +++++++++++ ...atewayConnectionRetryTimeoutStateTest.java | 28 +++++++++++++++++++ .../server/vcn/VcnGatewayConnectionTest.java | 23 +++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f7d61367c8..0d91e47625 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -514,7 +514,11 @@ public class Vcn extends Handler { } private String getLogPrefix() { - return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] "; + return "[" + + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + + "-" + + System.identityHashCode(this) + + "] "; } private void logVdbg(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 493697049f..c6f3f73d0c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -714,6 +714,18 @@ public class VcnGatewayConnection extends StateMachine { protected void onQuitting() { logDbg("Quitting VcnGatewayConnection"); + if (mNetworkAgent != null) { + logWtf("NetworkAgent was non-null in onQuitting"); + mNetworkAgent.unregister(); + mNetworkAgent = null; + } + + if (mIkeSession != null) { + logWtf("IkeSession was non-null in onQuitting"); + mIkeSession.kill(); + mIkeSession = null; + } + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); @@ -1863,6 +1875,7 @@ public class VcnGatewayConnection extends StateMachine { if (mUnderlying == null) { logWtf("Underlying network was null in retry state"); + teardownNetwork(); transitionTo(mDisconnectedState); } else { // Safe to blindly set up, as it is cancelled and cleared on exiting this state @@ -1879,6 +1892,7 @@ public class VcnGatewayConnection extends StateMachine { // If new underlying is null, all networks were lost; go back to disconnected. if (mUnderlying == null) { + teardownNetwork(); transitionTo(mDisconnectedState); return; } else if (oldUnderlying != null @@ -2134,6 +2148,8 @@ public class VcnGatewayConnection extends StateMachine { + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + mConnectionConfig.getGatewayConnectionName() + + "-" + + System.identityHashCode(this) + "] "; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index a88f112f45..69407657b3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -16,10 +16,16 @@ package com.android.server.vcn; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; + 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.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -33,16 +39,20 @@ import org.junit.runner.RunWith; @SmallTest public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase { private long mFirstRetryInterval; + private VcnNetworkAgent mNetworkAgent; @Before public void setUp() throws Exception { super.setUp(); mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0]; + mNetworkAgent = mock(VcnNetworkAgent.class); mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); mTestLooper.dispatchAll(); + + mGatewayConnection.setNetworkAgent(mNetworkAgent); } @Test @@ -54,6 +64,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -65,6 +78,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -76,6 +92,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } @Test @@ -93,6 +112,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -108,6 +130,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } @Test @@ -117,5 +142,8 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); assertFalse(mGatewayConnection.isQuitting()); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a4f95e03e9..83610e0b7a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -24,8 +24,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.eq; @@ -191,4 +195,23 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verify(mDisconnectRequestAlarm).cancel(); } + + @Test + public void testQuittingCleansUpPersistentState() { + final VcnIkeSession vcnIkeSession = mock(VcnIkeSession.class); + final VcnNetworkAgent vcnNetworkAgent = mock(VcnNetworkAgent.class); + + mGatewayConnection.setIkeSession(vcnIkeSession); + mGatewayConnection.setNetworkAgent(vcnNetworkAgent); + + mGatewayConnection.quitNow(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getIkeSession()); + verify(vcnIkeSession).kill(); + assertNull(mGatewayConnection.getNetworkAgent()); + verify(vcnNetworkAgent).unregister(); + + verifyWakeLockReleased(); + } } From 8011c3acfda75fc725ea2e29f34f74621897707b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 25 Jun 2021 12:03:10 -0700 Subject: [PATCH 0255/1057] Fix dangling NetworkAgent This change fixes the potential for a networkAgent to be left dangling, due to a situation where a VcnGatewayConnection shuts down, but fails to unregister it's NetworkAgent. The root cause was that the NetworkAgent was not unregistered when moving to the DisconnectedState from the RetryTimeoutState, and the new state assumed that there was no NetworkAgent, and thus failed to close it when disconnecting. Thus, this change ensures that the NetworkAgent is closed before moving to the DisconnectedState. Additionally, it adds safety-checks to onQuitting(), ensuring that if all else fails, these fields are cleaned up. Lastly, this change adds the specific gateway reference to facilitate future debugging of issues such as this where there is potential for duplicate networks, or gateway connections. Bug: 191707296 Test: atest FrameworksVcnTests Change-Id: I84cd43a0c136662f5c2d229650f1f5f889e6f144 Merged-In: I84cd43a0c136662f5c2d229650f1f5f889e6f144 (cherry picked from commit 7207a83ca8796ced7e7fc4f7eba2433ecaa2ff0f) --- .../src/com/android/server/vcn/Vcn.java | 6 +++- .../server/vcn/VcnGatewayConnection.java | 16 +++++++++++ ...atewayConnectionRetryTimeoutStateTest.java | 28 +++++++++++++++++++ .../server/vcn/VcnGatewayConnectionTest.java | 23 +++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 95a06fcff7..44a6d13153 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -518,7 +518,11 @@ public class Vcn extends Handler { } private String getLogPrefix() { - return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] "; + return "[" + + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + + "-" + + System.identityHashCode(this) + + "] "; } private void logVdbg(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 493697049f..c6f3f73d0c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -714,6 +714,18 @@ public class VcnGatewayConnection extends StateMachine { protected void onQuitting() { logDbg("Quitting VcnGatewayConnection"); + if (mNetworkAgent != null) { + logWtf("NetworkAgent was non-null in onQuitting"); + mNetworkAgent.unregister(); + mNetworkAgent = null; + } + + if (mIkeSession != null) { + logWtf("IkeSession was non-null in onQuitting"); + mIkeSession.kill(); + mIkeSession = null; + } + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); @@ -1863,6 +1875,7 @@ public class VcnGatewayConnection extends StateMachine { if (mUnderlying == null) { logWtf("Underlying network was null in retry state"); + teardownNetwork(); transitionTo(mDisconnectedState); } else { // Safe to blindly set up, as it is cancelled and cleared on exiting this state @@ -1879,6 +1892,7 @@ public class VcnGatewayConnection extends StateMachine { // If new underlying is null, all networks were lost; go back to disconnected. if (mUnderlying == null) { + teardownNetwork(); transitionTo(mDisconnectedState); return; } else if (oldUnderlying != null @@ -2134,6 +2148,8 @@ public class VcnGatewayConnection extends StateMachine { + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + mConnectionConfig.getGatewayConnectionName() + + "-" + + System.identityHashCode(this) + "] "; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index a88f112f45..69407657b3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -16,10 +16,16 @@ package com.android.server.vcn; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; + 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.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -33,16 +39,20 @@ import org.junit.runner.RunWith; @SmallTest public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase { private long mFirstRetryInterval; + private VcnNetworkAgent mNetworkAgent; @Before public void setUp() throws Exception { super.setUp(); mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0]; + mNetworkAgent = mock(VcnNetworkAgent.class); mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); mTestLooper.dispatchAll(); + + mGatewayConnection.setNetworkAgent(mNetworkAgent); } @Test @@ -54,6 +64,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -65,6 +78,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -76,6 +92,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } @Test @@ -93,6 +112,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); + + assertNotNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent, never()).unregister(); } @Test @@ -108,6 +130,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } @Test @@ -117,5 +142,8 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); assertFalse(mGatewayConnection.isQuitting()); + + assertNull(mGatewayConnection.getNetworkAgent()); + verify(mNetworkAgent).unregister(); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a4f95e03e9..83610e0b7a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -24,8 +24,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.eq; @@ -191,4 +195,23 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verify(mDisconnectRequestAlarm).cancel(); } + + @Test + public void testQuittingCleansUpPersistentState() { + final VcnIkeSession vcnIkeSession = mock(VcnIkeSession.class); + final VcnNetworkAgent vcnNetworkAgent = mock(VcnNetworkAgent.class); + + mGatewayConnection.setIkeSession(vcnIkeSession); + mGatewayConnection.setNetworkAgent(vcnNetworkAgent); + + mGatewayConnection.quitNow(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getIkeSession()); + verify(vcnIkeSession).kill(); + assertNull(mGatewayConnection.getNetworkAgent()); + verify(vcnNetworkAgent).unregister(); + + verifyWakeLockReleased(); + } } From 6abcec4dd023ee3c9f3d6bc8677865d39a4a1ef7 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 1 Jul 2021 15:39:03 -0700 Subject: [PATCH 0256/1057] Fix VCN test by using IPv4 address The exsiting tests rely on NAT detection payloads being sent. As part of fixing an IPv6 encap issue, the IKE library no longer sends NAT detection payloads on IPv6, meaning that to preserve the test, we must simulate an IKE exchange on IPv4. Bug: 188570938 Test: atest VcnManagerTest Change-Id: Iae3c93fd8352b47fb9eb8cff34fd5cdf0ad794ba --- .../android/net/vcn/cts/VcnManagerTest.java | 20 +++++++++---------- .../src/android/net/vcn/cts/VcnTestBase.java | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e12d9c00b4..e4f224f538 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -63,7 +63,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.net.Inet6Address; +import java.net.InetAddress; import java.util.Collections; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -81,10 +81,10 @@ public class VcnManagerTest extends VcnTestBase { private static final int TEST_NETWORK_MTU = 1500; - private static final Inet6Address LOCAL_V6_ADDRESS = - (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); - private static final Inet6Address SECONDARY_LOCAL_V6_ADDRESS = - (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::3"); + private static final InetAddress LOCAL_ADDRESS = + InetAddresses.parseNumericAddress("198.51.100.1"); + private static final InetAddress SECONDARY_LOCAL_ADDRESS = + InetAddresses.parseNumericAddress("198.51.100.2"); private static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); @@ -362,7 +362,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED @@ -433,7 +433,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before @@ -541,7 +541,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before @@ -567,7 +567,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - SECONDARY_LOCAL_V6_ADDRESS); + SECONDARY_LOCAL_ADDRESS); try { assertNotNull("No test network found", secondaryTestNetworkWrapper.tunNetwork); @@ -636,7 +636,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index 4b79fa9248..d7485b13c4 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -60,7 +60,8 @@ public class VcnTestBase { .addDhGroup(DH_GROUP_2048_BIT_MODP) .build(); - final String serverHostname = "2001:db8:1::100"; + // TODO: b/192610392 Improve VcnManagerTest CTS by adding IPv6 test case. + final String serverHostname = "192.0.2.1"; final String testLocalId = "client.test.ike.android.net"; final String testRemoteId = "server.test.ike.android.net"; final byte[] psk = "ikeAndroidPsk".getBytes(); From 87678d1bc945ff462ce5cb6cbc10983262f7f066 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 28 Jun 2021 17:27:28 -0700 Subject: [PATCH 0257/1057] Add VCN underlying networks This change declares underlying networks for the VCN for the purposes of app data accounting Bug: 190620024 Test: atest FrameworksVcnTests Change-Id: Ida2cd5975250604064b0baed00bc7c201ea97c5e --- .../server/vcn/UnderlyingNetworkTracker.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 43 ++++++++++++++++++- .../vcn/UnderlyingNetworkTrackerTest.java | 11 +++++ ...cnGatewayConnectionConnectedStateTest.java | 6 +++ .../server/vcn/VcnGatewayConnectionTest.java | 4 +- 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ee7bf5f0d9..0b8ed18c70 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -409,7 +409,7 @@ public class UnderlyingNetworkTracker { } private void reevaluateNetworks() { - if (mRouteSelectionCallback == null) { + if (mIsQuitting || mRouteSelectionCallback == null) { return; // UnderlyingNetworkTracker has quit. } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 493697049f..c3a5892760 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -75,6 +75,7 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.PowerManager.WakeLock; +import android.os.Process; import android.os.SystemClock; import android.util.ArraySet; import android.util.Slog; @@ -97,6 +98,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -925,6 +927,14 @@ public class VcnGatewayConnection extends StateMachine { private WakeupMessage createScheduledAlarm( @NonNull String cmdName, Message delayedMessage, long delay) { + final Handler handler = getHandler(); + if (handler == null) { + logWarn( + "Attempted to schedule alarm after StateMachine has quit", + new IllegalStateException()); + return null; // StateMachine has already quit. + } + // WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable // at the scheduled time. dispatchMessage() immediately executes and there may be queued // events that resolve the scheduled alarm pending in the queue. So, use the Runnable to @@ -933,7 +943,7 @@ public class VcnGatewayConnection extends StateMachine { final WakeupMessage alarm = mDeps.newWakeupMessage( mVcnContext, - getHandler(), + handler, cmdName, () -> sendMessageAndAcquireWakeLock(delayedMessage)); alarm.schedule(mDeps.getElapsedRealTime() + delay); @@ -1560,6 +1570,9 @@ public class VcnGatewayConnection extends StateMachine { agent.sendNetworkCapabilities(caps); agent.sendLinkProperties(lp); + + agent.setUnderlyingNetworks( + mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); } protected VcnNetworkAgent buildNetworkAgent( @@ -1601,6 +1614,10 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { + if (mIsQuitting) { + return; // Ignore; VcnGatewayConnection quitting or already quit + } + switch (status) { case NetworkAgent.VALIDATION_STATUS_VALID: clearFailedAttemptCounterAndSafeModeAlarm(); @@ -1620,6 +1637,8 @@ public class VcnGatewayConnection extends StateMachine { } /* validationStatusCallback */); agent.register(); + agent.setUnderlyingNetworks( + mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); agent.markConnected(); return agent; @@ -1958,7 +1977,7 @@ public class VcnGatewayConnection extends StateMachine { final int[] underlyingAdminUids = underlyingCaps.getAdministratorUids(); Arrays.sort(underlyingAdminUids); // Sort to allow contains check below. - final int[] adminUids; + int[] adminUids; if (underlyingCaps.getOwnerUid() > 0 // No owner UID specified && 0 > Arrays.binarySearch(// Owner UID not found in admin UID list. underlyingAdminUids, underlyingCaps.getOwnerUid())) { @@ -1968,6 +1987,11 @@ public class VcnGatewayConnection extends StateMachine { } else { adminUids = underlyingAdminUids; } + + // Set owner & administrator UID + builder.setOwnerUid(Process.myUid()); + adminUids = Arrays.copyOf(adminUids, adminUids.length + 1); + adminUids[adminUids.length - 1] = Process.myUid(); builder.setAdministratorUids(adminUids); builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps()); @@ -2154,6 +2178,16 @@ public class VcnGatewayConnection extends StateMachine { LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } + private void logWarn(String msg) { + Slog.w(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg); + } + + private void logWarn(String msg, Throwable tr) { + Slog.w(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); @@ -2531,6 +2565,11 @@ public class VcnGatewayConnection extends StateMachine { mImpl.sendLinkProperties(lp); } + /** Sends new NetworkCapabilities for the underlying NetworkAgent */ + public void setUnderlyingNetworks(@Nullable List underlyingNetworks) { + mImpl.setUnderlyingNetworks(underlyingNetworks); + } + /** Retrieves the Network for the underlying NetworkAgent */ @Nullable public Network getNetwork() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index f91575b670..5af69b5d1b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -476,5 +476,16 @@ public class UnderlyingNetworkTrackerTest { verifyNoMoreInteractions(mNetworkTrackerCb); } + @Test + public void testRecordTrackerCallbackNotifiedAfterTeardown() { + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); + mUnderlyingNetworkTracker.teardown(); + + cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); + + // Verify that the only call was during onAvailable() + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); + } + // TODO (b/187991063): Add tests for network prioritization } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 9c93f81114..6bfbfb1c84 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -48,6 +48,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static java.util.Collections.singletonList; + import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; @@ -233,6 +235,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mNetworkAgent).sendLinkProperties( argThat(lp -> expectedMtu == lp.getMtu() && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); + verify(mNetworkAgent) + .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_2.network))); } private void triggerChildOpened() { @@ -293,6 +297,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any()); verify(mNetworkAgent).register(); + verify(mNetworkAgent) + .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network))); verify(mNetworkAgent).markConnected(); verify(mIpSecSvc) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a4f95e03e9..f543f35613 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -64,7 +64,7 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { - private static final int TEST_UID = Process.myUid(); + private static final int TEST_UID = Process.myUid() + 1; private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; @@ -133,7 +133,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } } - assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); + assertArrayEquals(new int[] {Process.myUid(), TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps()); assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps()); From 6359ca8ace020b681997483d6f330c72ed340747 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Jul 2021 16:34:33 -0700 Subject: [PATCH 0258/1057] Request location info in UnderlyingNetworkListener This change ensures that the UnderlyingNetworkListener receives location-sensitive fields in order to proxy the location sensitive fields in the VcnTransportInfo Bug: 192587440 Test: manual tests Test: atest FrameworksVcnTests Change-Id: Id42ae2e373d909424c3f213412ea4731ee01fa2b --- .../src/com/android/server/vcn/UnderlyingNetworkTracker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ee7bf5f0d9..3214e921e0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -460,6 +460,10 @@ public class UnderlyingNetworkTracker { private final Map mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); + UnderlyingNetworkListener() { + super(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO); + } + private TreeSet getSortedUnderlyingNetworks() { TreeSet sorted = new TreeSet<>( From 15fd9d6acb8b2d6af73c319b2d96680d8279a1b4 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 2 Jul 2021 08:36:24 +0000 Subject: [PATCH 0259/1057] Request location info in UnderlyingNetworkListener This change ensures that the UnderlyingNetworkListener receives location-sensitive fields in order to proxy the location sensitive fields in the VcnTransportInfo Bug: 192587440 Test: manual tests Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1754781 Merged-In: Id42ae2e373d909424c3f213412ea4731ee01fa2b Change-Id: Id42ae2e373d909424c3f213412ea4731ee01fa2b --- .../src/com/android/server/vcn/UnderlyingNetworkTracker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ee7bf5f0d9..3214e921e0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -460,6 +460,10 @@ public class UnderlyingNetworkTracker { private final Map mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); + UnderlyingNetworkListener() { + super(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO); + } + private TreeSet getSortedUnderlyingNetworks() { TreeSet sorted = new TreeSet<>( From aa28d585741ca153b2847f209c5ae2cf93b848c6 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 2 Jul 2021 19:12:53 +0000 Subject: [PATCH 0260/1057] Add VCN underlying networks This change declares underlying networks for the VCN for the purposes of app data accounting Bug: 190620024 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1750241 Merged-In: Ida2cd5975250604064b0baed00bc7c201ea97c5e Change-Id: Ida2cd5975250604064b0baed00bc7c201ea97c5e --- .../server/vcn/UnderlyingNetworkTracker.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 43 ++++++++++++++++++- .../vcn/UnderlyingNetworkTrackerTest.java | 11 +++++ ...cnGatewayConnectionConnectedStateTest.java | 6 +++ .../server/vcn/VcnGatewayConnectionTest.java | 4 +- 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java index ee7bf5f0d9..0b8ed18c70 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -409,7 +409,7 @@ public class UnderlyingNetworkTracker { } private void reevaluateNetworks() { - if (mRouteSelectionCallback == null) { + if (mIsQuitting || mRouteSelectionCallback == null) { return; // UnderlyingNetworkTracker has quit. } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index c6f3f73d0c..38427697a9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -75,6 +75,7 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.PowerManager.WakeLock; +import android.os.Process; import android.os.SystemClock; import android.util.ArraySet; import android.util.Slog; @@ -97,6 +98,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -937,6 +939,14 @@ public class VcnGatewayConnection extends StateMachine { private WakeupMessage createScheduledAlarm( @NonNull String cmdName, Message delayedMessage, long delay) { + final Handler handler = getHandler(); + if (handler == null) { + logWarn( + "Attempted to schedule alarm after StateMachine has quit", + new IllegalStateException()); + return null; // StateMachine has already quit. + } + // WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable // at the scheduled time. dispatchMessage() immediately executes and there may be queued // events that resolve the scheduled alarm pending in the queue. So, use the Runnable to @@ -945,7 +955,7 @@ public class VcnGatewayConnection extends StateMachine { final WakeupMessage alarm = mDeps.newWakeupMessage( mVcnContext, - getHandler(), + handler, cmdName, () -> sendMessageAndAcquireWakeLock(delayedMessage)); alarm.schedule(mDeps.getElapsedRealTime() + delay); @@ -1572,6 +1582,9 @@ public class VcnGatewayConnection extends StateMachine { agent.sendNetworkCapabilities(caps); agent.sendLinkProperties(lp); + + agent.setUnderlyingNetworks( + mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); } protected VcnNetworkAgent buildNetworkAgent( @@ -1613,6 +1626,10 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { + if (mIsQuitting) { + return; // Ignore; VcnGatewayConnection quitting or already quit + } + switch (status) { case NetworkAgent.VALIDATION_STATUS_VALID: clearFailedAttemptCounterAndSafeModeAlarm(); @@ -1632,6 +1649,8 @@ public class VcnGatewayConnection extends StateMachine { } /* validationStatusCallback */); agent.register(); + agent.setUnderlyingNetworks( + mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); agent.markConnected(); return agent; @@ -1972,7 +1991,7 @@ public class VcnGatewayConnection extends StateMachine { final int[] underlyingAdminUids = underlyingCaps.getAdministratorUids(); Arrays.sort(underlyingAdminUids); // Sort to allow contains check below. - final int[] adminUids; + int[] adminUids; if (underlyingCaps.getOwnerUid() > 0 // No owner UID specified && 0 > Arrays.binarySearch(// Owner UID not found in admin UID list. underlyingAdminUids, underlyingCaps.getOwnerUid())) { @@ -1982,6 +2001,11 @@ public class VcnGatewayConnection extends StateMachine { } else { adminUids = underlyingAdminUids; } + + // Set owner & administrator UID + builder.setOwnerUid(Process.myUid()); + adminUids = Arrays.copyOf(adminUids, adminUids.length + 1); + adminUids[adminUids.length - 1] = Process.myUid(); builder.setAdministratorUids(adminUids); builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps()); @@ -2170,6 +2194,16 @@ public class VcnGatewayConnection extends StateMachine { LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } + private void logWarn(String msg) { + Slog.w(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg); + } + + private void logWarn(String msg, Throwable tr) { + Slog.w(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); @@ -2547,6 +2581,11 @@ public class VcnGatewayConnection extends StateMachine { mImpl.sendLinkProperties(lp); } + /** Sends new NetworkCapabilities for the underlying NetworkAgent */ + public void setUnderlyingNetworks(@Nullable List underlyingNetworks) { + mImpl.setUnderlyingNetworks(underlyingNetworks); + } + /** Retrieves the Network for the underlying NetworkAgent */ @Nullable public Network getNetwork() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index f91575b670..5af69b5d1b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -476,5 +476,16 @@ public class UnderlyingNetworkTrackerTest { verifyNoMoreInteractions(mNetworkTrackerCb); } + @Test + public void testRecordTrackerCallbackNotifiedAfterTeardown() { + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); + mUnderlyingNetworkTracker.teardown(); + + cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); + + // Verify that the only call was during onAvailable() + verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); + } + // TODO (b/187991063): Add tests for network prioritization } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 9c93f81114..6bfbfb1c84 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -48,6 +48,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static java.util.Collections.singletonList; + import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; @@ -233,6 +235,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mNetworkAgent).sendLinkProperties( argThat(lp -> expectedMtu == lp.getMtu() && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); + verify(mNetworkAgent) + .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_2.network))); } private void triggerChildOpened() { @@ -293,6 +297,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any()); verify(mNetworkAgent).register(); + verify(mNetworkAgent) + .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network))); verify(mNetworkAgent).markConnected(); verify(mIpSecSvc) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 83610e0b7a..a700171353 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -68,7 +68,7 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { - private static final int TEST_UID = Process.myUid(); + private static final int TEST_UID = Process.myUid() + 1; private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; @@ -137,7 +137,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } } - assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); + assertArrayEquals(new int[] {Process.myUid(), TEST_UID}, vcnCaps.getAdministratorUids()); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps()); assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps()); From d0dc52e64f258f09f2b2de8af4ef38bd39023903 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 9 Jul 2021 00:50:24 +0000 Subject: [PATCH 0261/1057] Fix VCN test by using IPv4 address The exsiting tests rely on NAT detection payloads being sent. As part of fixing an IPv6 encap issue, the IKE library no longer sends NAT detection payloads on IPv6, meaning that to preserve the test, we must simulate an IKE exchange on IPv4. Bug: 188570938 Test: atest VcnManagerTest Original-Change: https://android-review.googlesource.com/1754790 Merged-In: Iae3c93fd8352b47fb9eb8cff34fd5cdf0ad794ba Change-Id: Iae3c93fd8352b47fb9eb8cff34fd5cdf0ad794ba --- .../android/net/vcn/cts/VcnManagerTest.java | 20 +++++++++---------- .../src/android/net/vcn/cts/VcnTestBase.java | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 2572593c6c..7ab8c9cf23 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -63,7 +63,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.net.Inet6Address; +import java.net.InetAddress; import java.util.Collections; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -81,10 +81,10 @@ public class VcnManagerTest extends VcnTestBase { private static final int TEST_NETWORK_MTU = 1500; - private static final Inet6Address LOCAL_V6_ADDRESS = - (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); - private static final Inet6Address SECONDARY_LOCAL_V6_ADDRESS = - (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::3"); + private static final InetAddress LOCAL_ADDRESS = + InetAddresses.parseNumericAddress("198.51.100.1"); + private static final InetAddress SECONDARY_LOCAL_ADDRESS = + InetAddresses.parseNumericAddress("198.51.100.2"); private static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); @@ -362,7 +362,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED @@ -436,7 +436,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before @@ -544,7 +544,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before @@ -570,7 +570,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - SECONDARY_LOCAL_V6_ADDRESS); + SECONDARY_LOCAL_ADDRESS); try { assertNotNull("No test network found", secondaryTestNetworkWrapper.tunNetwork); @@ -639,7 +639,7 @@ public class VcnManagerTest extends VcnTestBase { TEST_NETWORK_MTU, true /* isMetered */, Collections.singleton(subId), - LOCAL_V6_ADDRESS); + LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); // Before the VCN starts, the test network should have NOT_VCN_MANAGED diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index 4b79fa9248..d7485b13c4 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -60,7 +60,8 @@ public class VcnTestBase { .addDhGroup(DH_GROUP_2048_BIT_MODP) .build(); - final String serverHostname = "2001:db8:1::100"; + // TODO: b/192610392 Improve VcnManagerTest CTS by adding IPv6 test case. + final String serverHostname = "192.0.2.1"; final String testLocalId = "client.test.ike.android.net"; final String testRemoteId = "server.test.ike.android.net"; final byte[] psk = "ikeAndroidPsk".getBytes(); From d97970e850e6be5f107734d690454cfd7dcf06c2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 14 Jul 2021 16:22:34 -0700 Subject: [PATCH 0262/1057] Limit VCNs to one running at a given time This change ensures that there is only ever one VCN running at a given point in time, and that if the device has switched to using a subscription in a different subscription group, the VCN will immediately tear down. This ensures that when on a DSDS device, when the VCN-enabled subscription is not the default/active subscription, the other subscription's network will never be outscored by the VCN, and thus get torn down. Bug: 190761448 Test: atest FrameworksVcnTests Test: Manual testing to ensure common functionality Change-Id: I8031fab7502880d38420058451df41f47567c458 --- .../android/server/VcnManagementService.java | 66 ++++- .../vcn/TelephonySubscriptionTracker.java | 57 ++++- .../server/VcnManagementServiceTest.java | 228 ++++++++++++++++-- .../vcn/TelephonySubscriptionTrackerTest.java | 45 +++- .../vcn/VcnGatewayConnectionTestBase.java | 4 +- 5 files changed, 355 insertions(+), 45 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 70b0fc126e..5d49fdc727 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -436,6 +437,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private boolean isActiveSubGroup( + @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) { + if (subGrp == null || snapshot == null) { + return false; + } + + return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -453,28 +463,49 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { + final ParcelUuid subGrp = entry.getKey(); + + // TODO(b/193687515): Support multiple VCNs active at the same time if (snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), entry.getValue().getProvisioningPackageName())) { - if (!mVcns.containsKey(entry.getKey())) { - startVcnLocked(entry.getKey(), entry.getValue()); + subGrp, entry.getValue().getProvisioningPackageName()) + && isActiveSubGroup(subGrp, snapshot)) { + if (!mVcns.containsKey(subGrp)) { + startVcnLocked(subGrp, entry.getValue()); } // Cancel any scheduled teardowns for active subscriptions - mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey())); + mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } // Schedule teardown of any VCN instances that have lost carrier privileges (after a // delay) for (Entry entry : mVcns.entrySet()) { - final VcnConfig config = mConfigs.get(entry.getKey()); + final ParcelUuid subGrp = entry.getKey(); + final VcnConfig config = mConfigs.get(subGrp); + final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); + final boolean isValidActiveDataSubIdNotInVcnSubGrp = + isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) + && !isActiveSubGroup(subGrp, snapshot); + + // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null || !snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), config.getProvisioningPackageName())) { - final ParcelUuid uuidToTeardown = entry.getKey(); + subGrp, config.getProvisioningPackageName()) + || !isActiveSubGrp) { + final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); + // TODO(b/193687515): Support multiple VCNs active at the same time + // If directly switching to a subscription not in the current group, + // teardown immediately to prevent other subscription's network from being + // outscored by the VCN. Otherwise, teardown after a delay to ensure that + // SIM profile switches do not trigger the VCN to cycle. + final long teardownDelayMs = + isValidActiveDataSubIdNotInVcnSubGrp + ? 0 + : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; mHandler.postDelayed(() -> { synchronized (mLock) { // Guard against case where this is run after a old instance was @@ -490,7 +521,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } } - }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + }, instanceToTeardown, teardownDelayMs); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); @@ -554,8 +585,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { logDbg("Starting VCN config for subGrp: " + subscriptionGroup); - // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active - // VCN. + // TODO(b/193687515): Support multiple VCNs active at the same time + if (!mVcns.isEmpty()) { + // Only one VCN supported at a time; teardown all others before starting new one + for (ParcelUuid uuidToTeardown : mVcns.keySet()) { + stopVcnLocked(uuidToTeardown); + } + } final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); @@ -583,7 +619,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Vcn vcn = mVcns.get(subscriptionGroup); vcn.updateConfig(config); } else { - startVcnLocked(subscriptionGroup, config); + // TODO(b/193687515): Support multiple VCNs active at the same time + if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) { + startVcnLocked(subscriptionGroup, config); + } } } @@ -1008,6 +1047,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + mLastSnapshot = Objects.requireNonNull(snapshot); + } + private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index fca706b707..a31c56a3b7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -36,6 +36,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; @@ -85,6 +86,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final SubscriptionManager mSubscriptionManager; @NonNull private final CarrierConfigManager mCarrierConfigManager; + @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener; + // TODO (Android T+): Add ability to handle multiple subIds per slot. @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @@ -112,6 +115,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener(); mSubscriptionChangedListener = new OnSubscriptionsChangedListener() { @@ -124,16 +128,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Registers the receivers, and starts tracking subscriptions. */ public void register() { + final HandlerExecutor executor = new HandlerExecutor(mHandler); + mContext.registerReceiver( this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( - new HandlerExecutor(mHandler), mSubscriptionChangedListener); + executor, mSubscriptionChangedListener); + mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); } /** Unregisters the receivers, and stops tracking subscriptions. */ public void unregister() { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); + mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); } /** @@ -185,7 +193,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); + new TelephonySubscriptionSnapshot( + mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -242,16 +251,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { + private final int mActiveDataSubId; private final Map mSubIdToInfoMap; private final Map> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = - new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap()); + new TelephonySubscriptionSnapshot( + INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap()); @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( + int activeDataSubId, @NonNull Map subIdToInfoMap, @NonNull Map> privilegedPackages) { + mActiveDataSubId = activeDataSubId; Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); @@ -265,6 +278,22 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets); } + /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */ + public int getActiveDataSubscriptionId() { + return mActiveDataSubId; + } + + /** Returns the active subscription group */ + @Nullable + public ParcelUuid getActiveDataSubscriptionGroup() { + final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId()); + if (info == null) { + return null; + } + + return info.getGroupUuid(); + } + /** Returns the active subscription groups */ @NonNull public Set getActiveSubscriptionGroups() { @@ -313,7 +342,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public int hashCode() { - return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); + return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -324,7 +353,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) + return mActiveDataSubId == other.mActiveDataSubId + && mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -333,6 +363,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); + pw.println("mActiveDataSubId: " + mActiveDataSubId); pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); @@ -342,7 +373,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToInfoMap=" + mSubIdToInfoMap + + "mActiveDataSubId=" + mActiveDataSubId + + ", mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } @@ -362,6 +394,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot); } + private class ActiveDataSubscriptionIdListener extends TelephonyCallback + implements TelephonyCallback.ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + handleSubscriptionsChanged(); + } + } + /** External static dependencies for test injection */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -369,5 +409,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) { return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle); } + + /** Gets the active Subscription ID */ + public int getActiveDataSubscriptionId() { + return SubscriptionManager.getActiveDataSubscriptionId(); + } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index b7a6d0ff76..7c7dc4d79e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -50,6 +51,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; @@ -99,6 +101,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.FileNotFoundException; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -227,6 +230,7 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + setupActiveSubscription(TEST_UUID_1); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); doReturn(mMockIBinder).when(mMockStatusCallback).asBinder(); @@ -300,23 +304,65 @@ public class VcnManagementServiceTest { } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set activeSubscriptionGroups) { + ParcelUuid activeDataSubGrp, Set activeSubscriptionGroups) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, Collections.emptyMap()); + activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap()); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set activeSubscriptionGroups, Map subIdToGroupMap) { + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */); + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + true /* hasCarrierPrivileges */); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap, + boolean hasCarrierPrivileges) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap, + boolean hasCarrierPrivileges) { + final TelephonySubscriptionSnapshot snapshot = + buildSubscriptionSnapshot( + activeDataSubId, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + cb.onNewSnapshot(snapshot); + + return snapshot; + } + + private TelephonySubscriptionSnapshot buildSubscriptionSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, Set activeSubscriptionGroups, Map subIdToGroupMap, boolean hasCarrierPrivileges) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); + doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup(); + doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId(); final Set privilegedPackages = (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) @@ -343,12 +389,19 @@ public class VcnManagementServiceTest { return subIds; }).when(snapshot).getAllSubIdsInGroup(any()); - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - cb.onNewSnapshot(snapshot); - return snapshot; } + private void setupActiveSubscription(ParcelUuid activeDataSubGrp) { + mVcnMgmtSvc.setLastSnapshot( + buildSubscriptionSnapshot( + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + Collections.emptySet(), + Collections.emptyMap(), + true /* hasCarrierPrivileges */)); + } + private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() { final ArgumentCaptor captor = ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class); @@ -372,25 +425,56 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); verify(mMockDeps) .newVcnContext( eq(mMockContext), eq(mTestLooper.getLooper()), any(VcnNetworkProvider.class), anyBoolean()); + + // Verify that only the VCN for the active data SIM was started. verify(mMockDeps) .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(mMockDeps, never()) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances() + throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); + + // Verify that a new VCN for UUID_2 was started, and the old instance was torn down + // immediately + verify(mMockDeps) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); } @Test public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Verify teardown after delay mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -399,20 +483,77 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate switch to different default data subscription that does not have a VCN. + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + mTestLooper.dispatchAll(); + + verify(vcn).teardownAsynchronously(); + assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); + } + + /** + * Tests an intermediate state where carrier privileges are marked as lost before active data + * subId changes during a SIM ejection. + * + *

      The expected outcome is that the VCN is torn down after a delay, as opposed to + * immediately. + */ + @Test + public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate privileges lost + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + @Test public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot( + INVALID_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); // Simulate new SIM loaded right during teardown delay. mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); // Verify that even after the full timeout duration, the VCN instance is not torn down mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -422,11 +563,13 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new // vcnInstance. @@ -434,6 +577,7 @@ public class VcnManagementServiceTest { VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); // Verify that new instance was different, and the old one was torn down @@ -537,6 +681,31 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception { + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2)); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + + verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any()); + } + + @Test + public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception { + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + // Use a different UUID to simulate a new VCN config. + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); + } + @Test public void testSetVcnConfigTestModeRequiresPermission() throws Exception { doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS")) @@ -561,7 +730,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); @@ -635,7 +804,9 @@ public class VcnManagementServiceTest { } @Test - public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { + public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception { + setupActiveSubscription(TEST_UUID_2); + // Use a different UUID to simulate a new VCN config. mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); @@ -646,12 +817,7 @@ public class VcnManagementServiceTest { // Verify Vcn is started verify(mMockDeps) - .newVcn( - eq(mVcnContext), - eq(TEST_UUID_2), - eq(TEST_VCN_CONFIG), - eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT), - any()); + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any()); // Verify Vcn is updated if it was previously started mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -693,7 +859,7 @@ public class VcnManagementServiceTest { // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are // privileged for. - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); @@ -760,6 +926,7 @@ public class VcnManagementServiceTest { int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); triggerSubscriptionTrackerCbAndGetSnapshot( + subGrp, Collections.singleton(subGrp), Collections.singletonMap(subId, subGrp), hasCarrierPrivileges); @@ -927,18 +1094,23 @@ public class VcnManagementServiceTest { @Test public void testSubscriptionSnapshotUpdateNotifiesVcn() { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2); TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2)); verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot)); } @Test public void testAddNewVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -948,6 +1120,8 @@ public class VcnManagementServiceTest { @Test public void testRemoveVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -958,10 +1132,13 @@ public class VcnManagementServiceTest { @Test public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); @@ -988,7 +1165,8 @@ public class VcnManagementServiceTest { private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1)); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -1014,7 +1192,8 @@ public class VcnManagementServiceTest { boolean hasPermissionsforSubGroup) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + triggerSubscriptionTrackerCbAndGetSnapshot( + subGroup, Collections.singleton(subGroup)); setupSubscriptionAndStartVcn( TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup); @@ -1089,6 +1268,7 @@ public class VcnManagementServiceTest { // timeout so the VCN goes inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index ca7463884d..1f0df62fe7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -54,6 +55,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -178,6 +180,14 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } + private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(TelephonyCallback.class); + verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture()); + + return (ActiveDataSubscriptionIdListener) captor.getValue(); + } + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); @@ -196,7 +206,14 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map subIdToInfoMap, Map> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages); + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + int activeSubId, + Map subIdToInfoMap, + Map> privilegedPackages) { + return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -249,6 +266,26 @@ public class TelephonySubscriptionTrackerTest { verifyNoActiveSubscriptions(); } + @Test + public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception { + setupReadySubIds(); + setPrivilegedPackagesForMock(Collections.emptyList()); + + doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId(); + final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener(); + listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2); + mTestLooper.dispatchAll(); + + ArgumentCaptor snapshotCaptor = + ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class); + verify(mCallback).onNewSnapshot(snapshotCaptor.capture()); + + TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue(); + assertNotNull(snapshot); + assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId()); + assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup()); + } + @Test public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages() throws Exception { @@ -371,7 +408,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +418,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index b97023a95d..a696b3ae28 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -127,7 +127,9 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); + TEST_SUB_ID, + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), + Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; From 3a41f12b8ce53c63b130881a5636a03096316d3d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 15 Jul 2021 19:41:53 -0700 Subject: [PATCH 0263/1057] Ensure VcnGatewayConnection#isQuitting never gets unset after being set This change ensures that the VcnGatewayConnection can never abort a quitting command; specifically, if a non-quitting disconnect request is processed after a quitting disconnect request, the isQuitting value MUST continue to stay set (as true). Failure to OR the values results in orphaned VcnGatewayConnection(s), and the VCN network thrashing. Additionally reduce verbosity of local logs, to ensure it better captures failures and logWtf(s) Bug: 192776413 Test: atest FrameworksVcnTests Change-Id: Iec8dae701838794261957609bae4e270eaa9cdc7 --- .../android/net/vcn/util/OneWayBoolean.java | 39 +++++++++++++++++++ .../android/server/VcnManagementService.java | 7 ++-- .../src/com/android/server/vcn/Vcn.java | 3 -- .../server/vcn/VcnGatewayConnection.java | 38 +++++++++++------- ...cnGatewayConnectionConnectedStateTest.java | 4 ++ ...nGatewayConnectionConnectingStateTest.java | 4 ++ ...atewayConnectionDisconnectedStateTest.java | 6 ++- ...tewayConnectionDisconnectingStateTest.java | 4 ++ ...atewayConnectionRetryTimeoutStateTest.java | 4 ++ 9 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java diff --git a/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java new file mode 100644 index 0000000000..e79bb2d254 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java @@ -0,0 +1,39 @@ +/* + * 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.server.vcn.util; + +/** + * OneWayBoolean is an abstraction for a boolean that MUST only ever be flipped from false to true + * + *

      This class allows the providing of a guarantee that a flag will never be flipped back after + * being set. + * + * @hide + */ +public class OneWayBoolean { + private boolean mValue = false; + + /** Get boolean value. */ + public boolean getValue() { + return mValue; + } + + /** Sets the value to true. */ + public void setTrue() { + mValue = true; + } +} diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 70b0fc126e..8a1c684a61 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -520,12 +520,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { - final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown); + // Remove in 2 steps. Make sure teardownAsync is triggered before removing from the map. + final Vcn vcnToTeardown = mVcns.get(uuidToTeardown); if (vcnToTeardown == null) { return; } vcnToTeardown.teardownAsynchronously(); + mVcns.remove(uuidToTeardown); // Now that the VCN is removed, notify all registered listeners to refresh their // UnderlyingNetworkPolicy. @@ -1011,18 +1013,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, msg); - LOCAL_LOG.log(TAG + " VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, msg); - LOCAL_LOG.log(TAG + " DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, msg, tr); - LOCAL_LOG.log(TAG + " DBG: " + msg + tr); } private void logErr(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 44a6d13153..9c3721b15f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -528,18 +528,15 @@ public class Vcn extends Handler { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 38427697a9..3c0a05b6ed 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -92,6 +92,7 @@ import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerC import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; +import com.android.server.vcn.util.OneWayBoolean; import java.io.IOException; import java.net.Inet4Address; @@ -551,8 +552,13 @@ public class VcnGatewayConnection extends StateMachine { *

      This variable is false for the lifecycle of the VcnGatewayConnection, until a command to * teardown has been received. This may be flipped due to events such as the Network becoming * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure. + * + *

      WARNING: Assignments to this MUST ALWAYS (except for testing) use the or operator ("|="), + * otherwise the flag may be flipped back to false after having been set to true. This could + * lead to a case where the Vcn parent instance has commanded a teardown, but a spurious + * non-quitting disconnect request could flip this back to true. */ - private boolean mIsQuitting = false; + private OneWayBoolean mIsQuitting = new OneWayBoolean(); /** * Whether the VcnGatewayConnection is in safe mode. @@ -794,7 +800,7 @@ public class VcnGatewayConnection extends StateMachine { private void acquireWakeLock() { mVcnContext.ensureRunningOnLooperThread(); - if (!mIsQuitting) { + if (!mIsQuitting.getValue()) { mWakeLock.acquire(); logVdbg("Wakelock acquired: " + mWakeLock); @@ -1297,7 +1303,9 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180526152): notify VcnStatusCallback for Network loss logDbg("Tearing down. Cause: " + info.reason); - mIsQuitting = info.shouldQuit; + if (info.shouldQuit) { + mIsQuitting.setTrue(); + } teardownNetwork(); @@ -1341,7 +1349,7 @@ public class VcnGatewayConnection extends StateMachine { private class DisconnectedState extends BaseState { @Override protected void enterState() { - if (mIsQuitting) { + if (mIsQuitting.getValue()) { quitNow(); // Ignore all queued events; cleanup is complete. } @@ -1365,7 +1373,7 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) { - mIsQuitting = true; + mIsQuitting.setTrue(); quitNow(); } @@ -1451,7 +1459,10 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); - mIsQuitting = info.shouldQuit; + if (info.shouldQuit) { + mIsQuitting.setTrue(); + } + teardownNetwork(); if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { @@ -1467,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SESSION_CLOSED: mIkeSession = null; - if (!mIsQuitting && mUnderlying != null) { + if (!mIsQuitting.getValue() && mUnderlying != null) { transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); } else { teardownNetwork(); @@ -1626,7 +1637,7 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { - if (mIsQuitting) { + if (mIsQuitting.getValue()) { return; // Ignore; VcnGatewayConnection quitting or already quit } @@ -2180,18 +2191,15 @@ public class VcnGatewayConnection extends StateMachine { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logWarn(String msg) { @@ -2238,7 +2246,7 @@ public class VcnGatewayConnection extends StateMachine { + (getCurrentState() == null ? null : getCurrentState().getClass().getSimpleName())); - pw.println("mIsQuitting: " + mIsQuitting); + pw.println("mIsQuitting: " + mIsQuitting.getValue()); pw.println("mIsInSafeMode: " + mIsInSafeMode); pw.println("mCurrentToken: " + mCurrentToken); pw.println("mFailedAttempts: " + mFailedAttempts); @@ -2275,12 +2283,12 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) boolean isQuitting() { - return mIsQuitting; + return mIsQuitting.getValue(); } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setIsQuitting(boolean isQuitting) { - mIsQuitting = isQuitting; + void setQuitting() { + mIsQuitting.setTrue(); } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 6bfbfb1c84..0f84f6ebe5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -578,6 +578,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index acc8bf98e9..d1f3a210d8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -127,6 +127,10 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index ac0edaa3b5..2056eea42c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -68,7 +68,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect true /* isMobileDataEnabled */, mDeps); - vgc.setIsQuitting(true); + vgc.setQuitting(); vgc.transitionTo(vgc.mDisconnectedState); mTestLooper.dispatchAll(); @@ -102,6 +102,10 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 9da8b451c9..78aefad9f8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -79,6 +79,10 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 69407657b3..1c859790a2 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -90,6 +90,10 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); From 1be1fb39a4d9ea8715e96a6087900501f317a64e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 16 Jul 2021 03:27:31 +0000 Subject: [PATCH 0264/1057] Limit VCNs to one running at a given time This change ensures that there is only ever one VCN running at a given point in time, and that if the device has switched to using a subscription in a different subscription group, the VCN will immediately tear down. This ensures that when on a DSDS device, when the VCN-enabled subscription is not the default/active subscription, the other subscription's network will never be outscored by the VCN, and thus get torn down. Bug: 190761448 Test: atest FrameworksVcnTests Test: Manual testing to ensure common functionality Original-Change: https://android-review.googlesource.com/1767050 Merged-In: I8031fab7502880d38420058451df41f47567c458 Change-Id: I8031fab7502880d38420058451df41f47567c458 --- .../android/server/VcnManagementService.java | 66 ++++- .../vcn/TelephonySubscriptionTracker.java | 57 ++++- .../server/VcnManagementServiceTest.java | 228 ++++++++++++++++-- .../vcn/TelephonySubscriptionTrackerTest.java | 45 +++- .../vcn/VcnGatewayConnectionTestBase.java | 4 +- 5 files changed, 355 insertions(+), 45 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f9fd108176..207a5e3db0 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -435,6 +436,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private boolean isActiveSubGroup( + @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) { + if (subGrp == null || snapshot == null) { + return false; + } + + return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -452,28 +462,49 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Start any VCN instances as necessary for (Entry entry : mConfigs.entrySet()) { + final ParcelUuid subGrp = entry.getKey(); + + // TODO(b/193687515): Support multiple VCNs active at the same time if (snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), entry.getValue().getProvisioningPackageName())) { - if (!mVcns.containsKey(entry.getKey())) { - startVcnLocked(entry.getKey(), entry.getValue()); + subGrp, entry.getValue().getProvisioningPackageName()) + && isActiveSubGroup(subGrp, snapshot)) { + if (!mVcns.containsKey(subGrp)) { + startVcnLocked(subGrp, entry.getValue()); } // Cancel any scheduled teardowns for active subscriptions - mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey())); + mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } // Schedule teardown of any VCN instances that have lost carrier privileges (after a // delay) for (Entry entry : mVcns.entrySet()) { - final VcnConfig config = mConfigs.get(entry.getKey()); + final ParcelUuid subGrp = entry.getKey(); + final VcnConfig config = mConfigs.get(subGrp); + final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); + final boolean isValidActiveDataSubIdNotInVcnSubGrp = + isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) + && !isActiveSubGroup(subGrp, snapshot); + + // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null || !snapshot.packageHasPermissionsForSubscriptionGroup( - entry.getKey(), config.getProvisioningPackageName())) { - final ParcelUuid uuidToTeardown = entry.getKey(); + subGrp, config.getProvisioningPackageName()) + || !isActiveSubGrp) { + final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); + // TODO(b/193687515): Support multiple VCNs active at the same time + // If directly switching to a subscription not in the current group, + // teardown immediately to prevent other subscription's network from being + // outscored by the VCN. Otherwise, teardown after a delay to ensure that + // SIM profile switches do not trigger the VCN to cycle. + final long teardownDelayMs = + isValidActiveDataSubIdNotInVcnSubGrp + ? 0 + : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; mHandler.postDelayed(() -> { synchronized (mLock) { // Guard against case where this is run after a old instance was @@ -489,7 +520,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } } - }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + }, instanceToTeardown, teardownDelayMs); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); @@ -553,8 +584,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { logDbg("Starting VCN config for subGrp: " + subscriptionGroup); - // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active - // VCN. + // TODO(b/193687515): Support multiple VCNs active at the same time + if (!mVcns.isEmpty()) { + // Only one VCN supported at a time; teardown all others before starting new one + for (ParcelUuid uuidToTeardown : mVcns.keySet()) { + stopVcnLocked(uuidToTeardown); + } + } final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); @@ -582,7 +618,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Vcn vcn = mVcns.get(subscriptionGroup); vcn.updateConfig(config); } else { - startVcnLocked(subscriptionGroup, config); + // TODO(b/193687515): Support multiple VCNs active at the same time + if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) { + startVcnLocked(subscriptionGroup, config); + } } } @@ -1007,6 +1046,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { + mLastSnapshot = Objects.requireNonNull(snapshot); + } + private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index fca706b707..a31c56a3b7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -36,6 +36,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; @@ -85,6 +86,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final SubscriptionManager mSubscriptionManager; @NonNull private final CarrierConfigManager mCarrierConfigManager; + @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener; + // TODO (Android T+): Add ability to handle multiple subIds per slot. @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @@ -112,6 +115,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener(); mSubscriptionChangedListener = new OnSubscriptionsChangedListener() { @@ -124,16 +128,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Registers the receivers, and starts tracking subscriptions. */ public void register() { + final HandlerExecutor executor = new HandlerExecutor(mHandler); + mContext.registerReceiver( this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( - new HandlerExecutor(mHandler), mSubscriptionChangedListener); + executor, mSubscriptionChangedListener); + mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); } /** Unregisters the receivers, and stops tracking subscriptions. */ public void unregister() { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); + mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); } /** @@ -185,7 +193,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); + new TelephonySubscriptionSnapshot( + mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -242,16 +251,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { + private final int mActiveDataSubId; private final Map mSubIdToInfoMap; private final Map> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = - new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap()); + new TelephonySubscriptionSnapshot( + INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap()); @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( + int activeDataSubId, @NonNull Map subIdToInfoMap, @NonNull Map> privilegedPackages) { + mActiveDataSubId = activeDataSubId; Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); @@ -265,6 +278,22 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets); } + /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */ + public int getActiveDataSubscriptionId() { + return mActiveDataSubId; + } + + /** Returns the active subscription group */ + @Nullable + public ParcelUuid getActiveDataSubscriptionGroup() { + final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId()); + if (info == null) { + return null; + } + + return info.getGroupUuid(); + } + /** Returns the active subscription groups */ @NonNull public Set getActiveSubscriptionGroups() { @@ -313,7 +342,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public int hashCode() { - return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); + return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -324,7 +353,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) + return mActiveDataSubId == other.mActiveDataSubId + && mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -333,6 +363,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); + pw.println("mActiveDataSubId: " + mActiveDataSubId); pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); @@ -342,7 +373,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToInfoMap=" + mSubIdToInfoMap + + "mActiveDataSubId=" + mActiveDataSubId + + ", mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } @@ -362,6 +394,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot); } + private class ActiveDataSubscriptionIdListener extends TelephonyCallback + implements TelephonyCallback.ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + handleSubscriptionsChanged(); + } + } + /** External static dependencies for test injection */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { @@ -369,5 +409,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) { return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle); } + + /** Gets the active Subscription ID */ + public int getActiveDataSubscriptionId() { + return SubscriptionManager.getActiveDataSubscriptionId(); + } } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index b7a6d0ff76..7c7dc4d79e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -50,6 +51,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; @@ -99,6 +101,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.FileNotFoundException; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -227,6 +230,7 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(true); mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + setupActiveSubscription(TEST_UUID_1); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); doReturn(mMockIBinder).when(mMockStatusCallback).asBinder(); @@ -300,23 +304,65 @@ public class VcnManagementServiceTest { } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set activeSubscriptionGroups) { + ParcelUuid activeDataSubGrp, Set activeSubscriptionGroups) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, Collections.emptyMap()); + activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap()); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( - Set activeSubscriptionGroups, Map subIdToGroupMap) { + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap) { return triggerSubscriptionTrackerCbAndGetSnapshot( - activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */); + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + true /* hasCarrierPrivileges */); } private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap, + boolean hasCarrierPrivileges) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, + Set activeSubscriptionGroups, + Map subIdToGroupMap, + boolean hasCarrierPrivileges) { + final TelephonySubscriptionSnapshot snapshot = + buildSubscriptionSnapshot( + activeDataSubId, + activeDataSubGrp, + activeSubscriptionGroups, + subIdToGroupMap, + hasCarrierPrivileges); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + cb.onNewSnapshot(snapshot); + + return snapshot; + } + + private TelephonySubscriptionSnapshot buildSubscriptionSnapshot( + int activeDataSubId, + ParcelUuid activeDataSubGrp, Set activeSubscriptionGroups, Map subIdToGroupMap, boolean hasCarrierPrivileges) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); + doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup(); + doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId(); final Set privilegedPackages = (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) @@ -343,12 +389,19 @@ public class VcnManagementServiceTest { return subIds; }).when(snapshot).getAllSubIdsInGroup(any()); - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - cb.onNewSnapshot(snapshot); - return snapshot; } + private void setupActiveSubscription(ParcelUuid activeDataSubGrp) { + mVcnMgmtSvc.setLastSnapshot( + buildSubscriptionSnapshot( + TEST_SUBSCRIPTION_ID, + activeDataSubGrp, + Collections.emptySet(), + Collections.emptyMap(), + true /* hasCarrierPrivileges */)); + } + private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() { final ArgumentCaptor captor = ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class); @@ -372,25 +425,56 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); verify(mMockDeps) .newVcnContext( eq(mMockContext), eq(mTestLooper.getLooper()), any(VcnNetworkProvider.class), anyBoolean()); + + // Verify that only the VCN for the active data SIM was started. verify(mMockDeps) .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(mMockDeps, never()) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances() + throws Exception { + // Add a record for a non-active SIM + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2))); + + // Verify that a new VCN for UUID_2 was started, and the old instance was torn down + // immediately + verify(mMockDeps) + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); } @Test public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Verify teardown after delay mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -399,20 +483,77 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate switch to different default data subscription that does not have a VCN. + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + mTestLooper.dispatchAll(); + + verify(vcn).teardownAsynchronously(); + assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); + } + + /** + * Tests an intermediate state where carrier privileges are marked as lost before active data + * subId changes during a SIM ejection. + * + *

      The expected outcome is that the VCN is torn down after a delay, as opposed to + * immediately. + */ + @Test + public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate privileges lost + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + @Test public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot( + INVALID_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); // Simulate new SIM loaded right during teardown delay. mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); // Verify that even after the full timeout duration, the VCN instance is not torn down mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -422,11 +563,13 @@ public class VcnManagementServiceTest { @Test public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet()); + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new // vcnInstance. @@ -434,6 +577,7 @@ public class VcnManagementServiceTest { VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); // Verify that new instance was different, and the old one was torn down @@ -537,6 +681,31 @@ public class VcnManagementServiceTest { verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception { + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2)); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + + verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any()); + } + + @Test + public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception { + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1); + + // Use a different UUID to simulate a new VCN config. + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any()); + verify(vcn).teardownAsynchronously(); + assertEquals(1, mVcnMgmtSvc.getAllVcns().size()); + assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1)); + assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2)); + } + @Test public void testSetVcnConfigTestModeRequiresPermission() throws Exception { doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS")) @@ -561,7 +730,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); @@ -635,7 +804,9 @@ public class VcnManagementServiceTest { } @Test - public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { + public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception { + setupActiveSubscription(TEST_UUID_2); + // Use a different UUID to simulate a new VCN config. mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); @@ -646,12 +817,7 @@ public class VcnManagementServiceTest { // Verify Vcn is started verify(mMockDeps) - .newVcn( - eq(mVcnContext), - eq(TEST_UUID_2), - eq(TEST_VCN_CONFIG), - eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT), - any()); + .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any()); // Verify Vcn is updated if it was previously started mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -693,7 +859,7 @@ public class VcnManagementServiceTest { // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are // privileged for. - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); @@ -760,6 +926,7 @@ public class VcnManagementServiceTest { int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); triggerSubscriptionTrackerCbAndGetSnapshot( + subGrp, Collections.singleton(subGrp), Collections.singletonMap(subId, subGrp), hasCarrierPrivileges); @@ -927,18 +1094,23 @@ public class VcnManagementServiceTest { @Test public void testSubscriptionSnapshotUpdateNotifiesVcn() { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); final Map vcnInstances = mVcnMgmtSvc.getAllVcns(); final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2); TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2)); verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot)); } @Test public void testAddNewVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -948,6 +1120,8 @@ public class VcnManagementServiceTest { @Test public void testRemoveVcnUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -958,10 +1132,13 @@ public class VcnManagementServiceTest { @Test public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + startAndGetVcnInstance(TEST_UUID_2); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, Collections.singleton(TEST_UUID_2), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); @@ -988,7 +1165,8 @@ public class VcnManagementServiceTest { private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1)); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); @@ -1014,7 +1192,8 @@ public class VcnManagementServiceTest { boolean hasPermissionsforSubGroup) throws Exception { TelephonySubscriptionSnapshot snapshot = - triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + triggerSubscriptionTrackerCbAndGetSnapshot( + subGroup, Collections.singleton(subGroup)); setupSubscriptionAndStartVcn( TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup); @@ -1089,6 +1268,7 @@ public class VcnManagementServiceTest { // timeout so the VCN goes inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index ca7463884d..1f0df62fe7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -54,6 +55,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -178,6 +180,14 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } + private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(TelephonyCallback.class); + verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture()); + + return (ActiveDataSubscriptionIdListener) captor.getValue(); + } + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); @@ -196,7 +206,14 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map subIdToInfoMap, Map> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages); + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + int activeSubId, + Map subIdToInfoMap, + Map> privilegedPackages) { + return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -249,6 +266,26 @@ public class TelephonySubscriptionTrackerTest { verifyNoActiveSubscriptions(); } + @Test + public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception { + setupReadySubIds(); + setPrivilegedPackagesForMock(Collections.emptyList()); + + doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId(); + final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener(); + listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2); + mTestLooper.dispatchAll(); + + ArgumentCaptor snapshotCaptor = + ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class); + verify(mCallback).onNewSnapshot(snapshotCaptor.capture()); + + TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue(); + assertNotNull(snapshot); + assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId()); + assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup()); + } + @Test public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages() throws Exception { @@ -371,7 +408,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +418,8 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); + new TelephonySubscriptionSnapshot( + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index b97023a95d..a696b3ae28 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -127,7 +127,9 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); + TEST_SUB_ID, + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), + Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; From c1f0bc07c81dddc654600433a3da9cc130aec59c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 16 Jul 2021 22:16:36 +0000 Subject: [PATCH 0265/1057] Ensure VcnGatewayConnection#isQuitting never gets unset after being set This change ensures that the VcnGatewayConnection can never abort a quitting command; specifically, if a non-quitting disconnect request is processed after a quitting disconnect request, the isQuitting value MUST continue to stay set (as true). Failure to OR the values results in orphaned VcnGatewayConnection(s), and the VCN network thrashing. Additionally reduce verbosity of local logs, to ensure it better captures failures and logWtf(s) Bug: 192776413 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1768623 Merged-In: Iec8dae701838794261957609bae4e270eaa9cdc7 Change-Id: Iec8dae701838794261957609bae4e270eaa9cdc7 --- .../android/net/vcn/util/OneWayBoolean.java | 39 +++++++++++++++++++ .../android/server/VcnManagementService.java | 7 ++-- .../src/com/android/server/vcn/Vcn.java | 3 -- .../server/vcn/VcnGatewayConnection.java | 38 +++++++++++------- ...cnGatewayConnectionConnectedStateTest.java | 4 ++ ...nGatewayConnectionConnectingStateTest.java | 4 ++ ...atewayConnectionDisconnectedStateTest.java | 6 ++- ...tewayConnectionDisconnectingStateTest.java | 4 ++ ...atewayConnectionRetryTimeoutStateTest.java | 4 ++ 9 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java diff --git a/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java new file mode 100644 index 0000000000..e79bb2d254 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java @@ -0,0 +1,39 @@ +/* + * 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.server.vcn.util; + +/** + * OneWayBoolean is an abstraction for a boolean that MUST only ever be flipped from false to true + * + *

      This class allows the providing of a guarantee that a flag will never be flipped back after + * being set. + * + * @hide + */ +public class OneWayBoolean { + private boolean mValue = false; + + /** Get boolean value. */ + public boolean getValue() { + return mValue; + } + + /** Sets the value to true. */ + public void setTrue() { + mValue = true; + } +} diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f9fd108176..867c0935ae 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -519,12 +519,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { - final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown); + // Remove in 2 steps. Make sure teardownAsync is triggered before removing from the map. + final Vcn vcnToTeardown = mVcns.get(uuidToTeardown); if (vcnToTeardown == null) { return; } vcnToTeardown.teardownAsynchronously(); + mVcns.remove(uuidToTeardown); // Now that the VCN is removed, notify all registered listeners to refresh their // UnderlyingNetworkPolicy. @@ -1010,18 +1012,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, msg); - LOCAL_LOG.log(TAG + " VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, msg); - LOCAL_LOG.log(TAG + " DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, msg, tr); - LOCAL_LOG.log(TAG + " DBG: " + msg + tr); } private void logErr(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 44a6d13153..9c3721b15f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -528,18 +528,15 @@ public class Vcn extends Handler { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logErr(String msg) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 38427697a9..3c0a05b6ed 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -92,6 +92,7 @@ import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerC import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; +import com.android.server.vcn.util.OneWayBoolean; import java.io.IOException; import java.net.Inet4Address; @@ -551,8 +552,13 @@ public class VcnGatewayConnection extends StateMachine { *

      This variable is false for the lifecycle of the VcnGatewayConnection, until a command to * teardown has been received. This may be flipped due to events such as the Network becoming * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure. + * + *

      WARNING: Assignments to this MUST ALWAYS (except for testing) use the or operator ("|="), + * otherwise the flag may be flipped back to false after having been set to true. This could + * lead to a case where the Vcn parent instance has commanded a teardown, but a spurious + * non-quitting disconnect request could flip this back to true. */ - private boolean mIsQuitting = false; + private OneWayBoolean mIsQuitting = new OneWayBoolean(); /** * Whether the VcnGatewayConnection is in safe mode. @@ -794,7 +800,7 @@ public class VcnGatewayConnection extends StateMachine { private void acquireWakeLock() { mVcnContext.ensureRunningOnLooperThread(); - if (!mIsQuitting) { + if (!mIsQuitting.getValue()) { mWakeLock.acquire(); logVdbg("Wakelock acquired: " + mWakeLock); @@ -1297,7 +1303,9 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180526152): notify VcnStatusCallback for Network loss logDbg("Tearing down. Cause: " + info.reason); - mIsQuitting = info.shouldQuit; + if (info.shouldQuit) { + mIsQuitting.setTrue(); + } teardownNetwork(); @@ -1341,7 +1349,7 @@ public class VcnGatewayConnection extends StateMachine { private class DisconnectedState extends BaseState { @Override protected void enterState() { - if (mIsQuitting) { + if (mIsQuitting.getValue()) { quitNow(); // Ignore all queued events; cleanup is complete. } @@ -1365,7 +1373,7 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) { - mIsQuitting = true; + mIsQuitting.setTrue(); quitNow(); } @@ -1451,7 +1459,10 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); - mIsQuitting = info.shouldQuit; + if (info.shouldQuit) { + mIsQuitting.setTrue(); + } + teardownNetwork(); if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { @@ -1467,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SESSION_CLOSED: mIkeSession = null; - if (!mIsQuitting && mUnderlying != null) { + if (!mIsQuitting.getValue() && mUnderlying != null) { transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); } else { teardownNetwork(); @@ -1626,7 +1637,7 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { - if (mIsQuitting) { + if (mIsQuitting.getValue()) { return; // Ignore; VcnGatewayConnection quitting or already quit } @@ -2180,18 +2191,15 @@ public class VcnGatewayConnection extends StateMachine { private void logVdbg(String msg) { if (VDBG) { Slog.v(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg); } } private void logDbg(String msg) { Slog.d(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg); } private void logDbg(String msg, Throwable tr) { Slog.d(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr); } private void logWarn(String msg) { @@ -2238,7 +2246,7 @@ public class VcnGatewayConnection extends StateMachine { + (getCurrentState() == null ? null : getCurrentState().getClass().getSimpleName())); - pw.println("mIsQuitting: " + mIsQuitting); + pw.println("mIsQuitting: " + mIsQuitting.getValue()); pw.println("mIsInSafeMode: " + mIsInSafeMode); pw.println("mCurrentToken: " + mCurrentToken); pw.println("mFailedAttempts: " + mFailedAttempts); @@ -2275,12 +2283,12 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) boolean isQuitting() { - return mIsQuitting; + return mIsQuitting.getValue(); } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setIsQuitting(boolean isQuitting) { - mIsQuitting = isQuitting; + void setQuitting() { + mIsQuitting.setTrue(); } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 6bfbfb1c84..0f84f6ebe5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -578,6 +578,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index acc8bf98e9..d1f3a210d8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -127,6 +127,10 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); assertTrue(mGatewayConnection.isQuitting()); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index ac0edaa3b5..2056eea42c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -68,7 +68,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect true /* isMobileDataEnabled */, mDeps); - vgc.setIsQuitting(true); + vgc.setQuitting(); vgc.transitionTo(vgc.mDisconnectedState); mTestLooper.dispatchAll(); @@ -102,6 +102,10 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 9da8b451c9..78aefad9f8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -79,6 +79,10 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec mGatewayConnection.teardownAsynchronously(); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 69407657b3..1c859790a2 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -90,6 +90,10 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); + // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */); From 1098c91ffe0f2e8689aafcca9ffb27f6176238c0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 19 Jul 2021 15:26:56 -0700 Subject: [PATCH 0266/1057] Set TRANSPORT_PRIMARY for VCN NetworkOffers and NetworkAgents This change sets TRANSPORT_PRIMARY for all NetworkScore objects passed to ConnectivityService by the VCN. Without this patch, a VCN in safe mode will never get any NetworkRequests, since the new Policy-based NetworkRanker always prioritizes a existing satisfier of a network, regardless of score. However, a higher-priority policy check ensures that a TRANSPORT_PRIMARY request is used if it exists. This changes the VCN to utilize that functionality. Bug: 194122634 Test: atest FrameworksVcnTests Change-Id: I3a298a6c4c594c6e224f3f05764614802c00e9b0 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 7 ++++++- .../com/android/server/vcn/VcnNetworkProviderTest.java | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 44a6d13153..871befe8be 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -599,7 +599,12 @@ public class Vcn extends Handler { /** Retrieves the network score for a VCN Network */ // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider static NetworkScore getNetworkScore() { - return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build(); + // TODO(b/193687515): Stop setting TRANSPORT_PRIMARY, define a TRANSPORT_VCN, and set in + // NetworkOffer/NetworkAgent. + return new NetworkScore.Builder() + .setLegacyInt(VCN_LEGACY_SCORE_INT) + .setTransportPrimary(true) + .build(); } /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index 72db55b3f4..e9026e22b6 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -87,8 +87,8 @@ public class VcnNetworkProviderTest { eq(mVcnNetworkProvider), argThat( score -> - score.getLegacyInt() - == Vcn.getNetworkScore().getLegacyInt()), + score.getLegacyInt() == Vcn.getNetworkScore().getLegacyInt() + && score.isTransportPrimary()), any(), any(), cbCaptor.capture()); From aa0abc71a38844c028c0e5069de98011d3a7bfa2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 21 Jul 2021 02:05:47 +0000 Subject: [PATCH 0267/1057] Set TRANSPORT_PRIMARY for VCN NetworkOffers and NetworkAgents This change sets TRANSPORT_PRIMARY for all NetworkScore objects passed to ConnectivityService by the VCN. Without this patch, a VCN in safe mode will never get any NetworkRequests, since the new Policy-based NetworkRanker always prioritizes a existing satisfier of a network, regardless of score. However, a higher-priority policy check ensures that a TRANSPORT_PRIMARY request is used if it exists. This changes the VCN to utilize that functionality. Bug: 194122634 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1772025 Merged-In: I3a298a6c4c594c6e224f3f05764614802c00e9b0 Change-Id: I3a298a6c4c594c6e224f3f05764614802c00e9b0 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 7 ++++++- .../com/android/server/vcn/VcnNetworkProviderTest.java | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 9c3721b15f..382398a210 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -596,7 +596,12 @@ public class Vcn extends Handler { /** Retrieves the network score for a VCN Network */ // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider static NetworkScore getNetworkScore() { - return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build(); + // TODO(b/193687515): Stop setting TRANSPORT_PRIMARY, define a TRANSPORT_VCN, and set in + // NetworkOffer/NetworkAgent. + return new NetworkScore.Builder() + .setLegacyInt(VCN_LEGACY_SCORE_INT) + .setTransportPrimary(true) + .build(); } /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java index 72db55b3f4..e9026e22b6 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -87,8 +87,8 @@ public class VcnNetworkProviderTest { eq(mVcnNetworkProvider), argThat( score -> - score.getLegacyInt() - == Vcn.getNetworkScore().getLegacyInt()), + score.getLegacyInt() == Vcn.getNetworkScore().getLegacyInt() + && score.isTransportPrimary()), any(), any(), cbCaptor.capture()); From 24af7cc3aea1db1e3fe73b9a4c111724368a8394 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 23 Jul 2021 11:48:42 -0700 Subject: [PATCH 0268/1057] Wait for cell network to connect before expecting a lost network. This change ensures that during VCN network bringup, the underlying cell network is connected before the test starts, ensuring that the expectation of it disconnecting will always be valid. Bug: 193482848 Test: atest --iterations 100 VcnManagerTest Change-Id: Iacc5631c09b3196b2044d210b7f7a4da122d9b78 --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 7ab8c9cf23..95eaff6b1c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -465,6 +465,7 @@ public class VcnManagerTest extends VcnTestBase { @NonNull Network cellNetwork, @NonNull VcnTestNetworkCallback cellNetworkCb) throws Exception { + cellNetworkCb.waitForAvailable(); mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for From 829a3f3fb472e0c07039395060b16fd699d19152 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 23 Jul 2021 11:51:09 -0700 Subject: [PATCH 0269/1057] Shorten safe mode timer in VCN test mode This change reduces the time required to test VCN safe mode in CTS, in order to meet the 30s CTS quality bar Bug: 193482882 Test: atest --iterations 10 android.net.vcn.cts.VcnManagerTest Change-Id: Ibbf7132d45a7a0e5554b74fda6b3e309ee2d9c44 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 3c0a05b6ed..450257fcde 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -195,6 +195,7 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int SAFEMODE_TIMEOUT_SECONDS = 30; + private static final int SAFEMODE_TIMEOUT_SECONDS_TEST_MODE = 10; private interface EventInfo {} @@ -1082,7 +1083,9 @@ public class VcnGatewayConnection extends StateMachine { createScheduledAlarm( SAFEMODE_TIMEOUT_ALARM, delayedMessage, - TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + mVcnContext.isInTestMode() + ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE) + : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); } private void cancelSafeModeAlarm() { From 7a10079d99b40ce6a303ed58d93a4b146450a931 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 23 Jul 2021 11:51:09 -0700 Subject: [PATCH 0270/1057] Shorten safe mode timer in VCN test mode This change reduces the time required to test VCN safe mode in CTS, in order to meet the 30s CTS quality bar Bug: 193482882 Test: atest --iterations 10 android.net.vcn.cts.VcnManagerTest Original-Change: googleplex-android-review.git.corp.google.com/15375749 Change-Id: Ibbf7132d45a7a0e5554b74fda6b3e309ee2d9c44 Merged-In: Ibbf7132d45a7a0e5554b74fda6b3e309ee2d9c44 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 38427697a9..dfecdbee2d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -194,6 +194,7 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int SAFEMODE_TIMEOUT_SECONDS = 30; + private static final int SAFEMODE_TIMEOUT_SECONDS_TEST_MODE = 10; private interface EventInfo {} @@ -1076,7 +1077,9 @@ public class VcnGatewayConnection extends StateMachine { createScheduledAlarm( SAFEMODE_TIMEOUT_ALARM, delayedMessage, - TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + mVcnContext.isInTestMode() + ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE) + : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); } private void cancelSafeModeAlarm() { From b7e26a3ae21d264e543ce3cd061a3406ff4cb43a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 23 Jul 2021 11:48:42 -0700 Subject: [PATCH 0271/1057] Wait for cell network to connect before expecting a lost network. This change ensures that during VCN network bringup, the underlying cell network is connected before the test starts, ensuring that the expectation of it disconnecting will always be valid. Bug: 193482848 Test: atest --iterations 100 VcnManagerTest Original-Change: googleplex-android-review.git.corp.google.com/15373067 Change-Id: Iacc5631c09b3196b2044d210b7f7a4da122d9b78 Merged-In: Iacc5631c09b3196b2044d210b7f7a4da122d9b78 --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e4f224f538..cf63243df3 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -462,6 +462,7 @@ public class VcnManagerTest extends VcnTestBase { @NonNull Network cellNetwork, @NonNull VcnTestNetworkCallback cellNetworkCb) throws Exception { + cellNetworkCb.waitForAvailable(); mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for From 1a6705c00e33a615d35c5281741f80f8619a36f2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 26 Jul 2021 12:26:08 -0700 Subject: [PATCH 0272/1057] Handle underlying network regaining NOT_VCN_MANAGED capability This change ensures that all VCN teardown tests (clearVcnConfig) properly handles the case where the underlying network regains the NOT_VCN_MANAGED capability before the VCN network is lost. This would trigger the request to switch to the underlying network, as opposed to losing the VCN network. Bug: 193482882 Test: atest --iterations 100 VcnManagerTest (on aosp_cf_x86_64) Change-Id: I2bfcdec6437a39273290bddf058a8392ed7e8ab7 --- .../android/net/vcn/cts/VcnManagerTest.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 95eaff6b1c..33df59574d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -31,6 +31,7 @@ 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.assertNull; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -530,9 +531,21 @@ public class VcnManagerTest extends VcnTestBase { throws Exception { mVcnManager.clearVcnConfig(subGrp); - // Expect VCN Network to disappear after VcnConfig is cleared - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); + // Expect VCN Network to disappear after VcnConfig is cleared. + if (mConnectivityManager.getNetworkCapabilities(vcnNetwork) != null) { + + // If not already torn down, wait for teardown. In the event that the underlying network + // has already regained the NOT_VCN_MANAGED bit (before the VCN's NetworkAgent teardown) + // the VCN network MAY be immediately replaced with the underlying Cell, which only + // fires an onAvailable for the new network, as opposed to an onLost() for the VCN + // network. In that case, check that the VCN network has been unregistered. + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + if (lostVcnNetwork != null) { + assertEquals(vcnNetwork, lostVcnNetwork); + } else { + assertNull(mConnectivityManager.getNetworkCapabilities(vcnNetwork)); + } + } // Else already torn down, pass. } @Test From ed417acc0c4c0fc5c96d7313340e505dafb86d34 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 27 Aug 2021 18:51:30 +0000 Subject: [PATCH 0273/1057] Always trigger safe mode callbacks This change ensures that safe mode callbacks are always triggered from the VcnGatewayConnection up, ensuring that if a gateway connection is restarted and successfully validates, it will notify the Vcn class, and kick it out of safe mode. Previously, if a VCN had entered safe mode, and a config was updated, the newly updated VcnGatewayConnection would be brought up as "not" in safe mode, and thus the onSafeModeStatusChanged() callback would never be fired if the new VcnGatewayConnection successfully connected. Calling onSafeModeStatusChanged() multiple times is safe, and serves as a "connection status changed" callback. Bug: 196841140 Test: atest FrameworksVcnTests Test: manual testing Change-Id: I43c82ada9e9429e8283be65ab73d13075dfd6038 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 14 ++++++++++++-- .../android/server/vcn/VcnGatewayConnection.java | 6 ++---- .../VcnGatewayConnectionConnectedStateTest.java | 6 ++++-- .../server/vcn/VcnGatewayConnectionTestBase.java | 9 ++++++--- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 382398a210..e0cc8e1820 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -352,7 +352,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { - logDbg("VcnGatewayConnection safe mode status changed"); + logVdbg("VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -368,7 +368,7 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); - logDbg( + logInfo( "Safe mode " + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } @@ -539,6 +539,16 @@ public class Vcn extends Handler { Slog.d(TAG, getLogPrefix() + msg, tr); } + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 450257fcde..7dec4e785f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1677,10 +1677,8 @@ public class VcnGatewayConnection extends StateMachine { mFailedAttempts = 0; cancelSafeModeAlarm(); - if (mIsInSafeMode) { - mIsInSafeMode = false; - mGatewayStatusCallback.onSafeModeStatusChanged(); - } + mIsInSafeMode = false; + mGatewayStatusCallback.onSafeModeStatusChanged(); } protected void applyTransform( diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 0f84f6ebe5..c9a8947ab5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -322,6 +322,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); verify(mSafeModeTimeoutAlarm).cancel(); assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); } @Test @@ -391,6 +392,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, false /* isInSafeMode */); assertFalse(mGatewayConnection.isInSafeMode()); } @@ -400,7 +402,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); - assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); // Trigger a failed validation, and the subsequent safemode timeout. triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); @@ -416,7 +418,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection runnableCaptor.getValue().run(); mTestLooper.dispatchAll(); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */); } private Consumer setupNetworkAndGetUnwantedCallback() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index a696b3ae28..64d0bca15c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -23,7 +23,6 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -301,6 +300,11 @@ public class VcnGatewayConnectionTestBase { expectCanceled); } + protected void verifySafeModeStateAndCallbackFired(int invocationCount, boolean isInSafeMode) { + verify(mGatewayStatusCallback, times(invocationCount)).onSafeModeStatusChanged(); + assertEquals(isInSafeMode, mGatewayConnection.isInSafeMode()); + } + protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( @NonNull State expectedState) { // Set a VcnNetworkAgent, and expect it to be unregistered and cleared @@ -314,9 +318,8 @@ public class VcnGatewayConnectionTestBase { delayedEvent.run(); mTestLooper.dispatchAll(); - verify(mGatewayStatusCallback).onSafeModeStatusChanged(); assertEquals(expectedState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1, true); verify(mockNetworkAgent).unregister(); assertNull(mGatewayConnection.getNetworkAgent()); From efc046e801876d4d71cb099c8293f0eebffe2119 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 Sep 2021 20:52:25 +0000 Subject: [PATCH 0274/1057] Always trigger safe mode callbacks This change ensures that safe mode callbacks are always triggered from the VcnGatewayConnection up, ensuring that if a gateway connection is restarted and successfully validates, it will notify the Vcn class, and kick it out of safe mode. Previously, if a VCN had entered safe mode, and a config was updated, the newly updated VcnGatewayConnection would be brought up as "not" in safe mode, and thus the onSafeModeStatusChanged() callback would never be fired if the new VcnGatewayConnection successfully connected. Calling onSafeModeStatusChanged() multiple times is safe, and serves as a "connection status changed" callback. Bug: 196841140 Test: atest FrameworksVcnTests Test: manual testing Original-Change: https://android-review.googlesource.com/1811936 Change-Id: I43c82ada9e9429e8283be65ab73d13075dfd6038 Merged-In: I856517924d0a767b63ea6127b7d4e39e09e93f2c (cherry picked from commit d1e5af169ae0ff32a3102bdbc585bbd3f9c1d992) --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 14 ++++++++++++-- .../android/server/vcn/VcnGatewayConnection.java | 6 ++---- .../VcnGatewayConnectionConnectedStateTest.java | 6 ++++-- .../server/vcn/VcnGatewayConnectionTestBase.java | 9 ++++++--- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 382398a210..e0cc8e1820 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -352,7 +352,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { - logDbg("VcnGatewayConnection safe mode status changed"); + logVdbg("VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -368,7 +368,7 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); - logDbg( + logInfo( "Safe mode " + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } @@ -539,6 +539,16 @@ public class Vcn extends Handler { Slog.d(TAG, getLogPrefix() + msg, tr); } + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 450257fcde..7dec4e785f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1677,10 +1677,8 @@ public class VcnGatewayConnection extends StateMachine { mFailedAttempts = 0; cancelSafeModeAlarm(); - if (mIsInSafeMode) { - mIsInSafeMode = false; - mGatewayStatusCallback.onSafeModeStatusChanged(); - } + mIsInSafeMode = false; + mGatewayStatusCallback.onSafeModeStatusChanged(); } protected void applyTransform( diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 0f84f6ebe5..c9a8947ab5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -322,6 +322,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); verify(mSafeModeTimeoutAlarm).cancel(); assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); } @Test @@ -391,6 +392,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, false /* isInSafeMode */); assertFalse(mGatewayConnection.isInSafeMode()); } @@ -400,7 +402,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); - assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); // Trigger a failed validation, and the subsequent safemode timeout. triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); @@ -416,7 +418,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection runnableCaptor.getValue().run(); mTestLooper.dispatchAll(); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */); } private Consumer setupNetworkAndGetUnwantedCallback() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index a696b3ae28..64d0bca15c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -23,7 +23,6 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -301,6 +300,11 @@ public class VcnGatewayConnectionTestBase { expectCanceled); } + protected void verifySafeModeStateAndCallbackFired(int invocationCount, boolean isInSafeMode) { + verify(mGatewayStatusCallback, times(invocationCount)).onSafeModeStatusChanged(); + assertEquals(isInSafeMode, mGatewayConnection.isInSafeMode()); + } + protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( @NonNull State expectedState) { // Set a VcnNetworkAgent, and expect it to be unregistered and cleared @@ -314,9 +318,8 @@ public class VcnGatewayConnectionTestBase { delayedEvent.run(); mTestLooper.dispatchAll(); - verify(mGatewayStatusCallback).onSafeModeStatusChanged(); assertEquals(expectedState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1, true); verify(mockNetworkAgent).unregister(); assertNull(mGatewayConnection.getNetworkAgent()); From 56580a4cc488c7d40d7101efd99508d0e5d1e59f Mon Sep 17 00:00:00 2001 From: Yinchu Chen Date: Fri, 22 Oct 2021 06:22:11 +0000 Subject: [PATCH 0275/1057] Add NET_CAPABILITY_INTERNET NetworkCapability for VcnManagerTest Fix: When wifi connected, cellNetworkCb.waitForAvailable() will return null. VcnManagerTest test case will fail and throw 'No cell network found' error. android.net.vcn.cts.VcnManagerTest#testVcnMigrationAfterNetworkDies android.net.vcn.cts.VcnManagerTest#testSetVcnConfigOnTestNetwork android.net.vcn.cts.VcnManagerTest#testVcnSafemodeOnTestNetwork Test: attest VcnManagerTest Bug: 203745087 Change-Id: I8e8195689a314583e6a926f1d73c9c44608a12ed Signed-off-by: Henry Zhuang --- .../android/net/vcn/cts/VcnManagerTest.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 33df59574d..9670611439 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -442,8 +442,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -563,8 +565,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -662,8 +666,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); From 4495de7e66b58da85c0f0bcedbf2d465cf0bb9ef Mon Sep 17 00:00:00 2001 From: Yinchu Chen Date: Fri, 22 Oct 2021 06:22:11 +0000 Subject: [PATCH 0276/1057] Add NET_CAPABILITY_INTERNET NetworkCapability for VcnManagerTest Fix: When wifi connected, cellNetworkCb.waitForAvailable() will return null. VcnManagerTest test case will fail and throw 'No cell network found' error. android.net.vcn.cts.VcnManagerTest#testVcnMigrationAfterNetworkDies android.net.vcn.cts.VcnManagerTest#testSetVcnConfigOnTestNetwork android.net.vcn.cts.VcnManagerTest#testVcnSafemodeOnTestNetwork Test: attest VcnManagerTest Bug: 203745087 Change-Id: I8e8195689a314583e6a926f1d73c9c44608a12ed Signed-off-by: Henry Zhuang --- .../android/net/vcn/cts/VcnManagerTest.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index f401d557d6..8376ccb460 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -439,8 +439,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -560,8 +562,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -661,8 +665,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); From 0f74b9bdf266d58dae2984b7befe4c0e29c918e4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 28 Oct 2021 21:45:12 +0000 Subject: [PATCH 0277/1057] Update CTS owners Test: None; updating owners only Change-Id: Iacdc58932b87a4cde3f4b997f131d5d30e0baae8 --- Vcn/tests/cts/OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS index 574aa9f118..b3efc7bcc7 100644 --- a/Vcn/tests/cts/OWNERS +++ b/Vcn/tests/cts/OWNERS @@ -1,3 +1,3 @@ # Bug component: 685852 nharold@google.com -junyin@google.com \ No newline at end of file +yangji@google.com \ No newline at end of file From 0076dd6360d7befeb7cddb9cf9a70ac9370dc9db Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Mon, 25 Oct 2021 09:43:35 +0000 Subject: [PATCH 0278/1057] Support encoding/decoding IkeSessionParams with IKE_OPTION_INITIAL_CONTACT This commit updates IkeSessionParamsUtils to be able to encode/decode IkeSessionParams with IKE_OPTION_INITIAL_CONTACT to/from a PersistableBundle If this option is set for an IKE Session, The INITIAL CONTACT message is sent to the peer to ensure that old security associations (SAs) on the peer are deleted. Bug: 186179788 Test: atest FrameworksIkeTests Change-Id: I4ecd36ae222d95a84e8e6897a219f8accb9ed83b --- .../net/vcn/persistablebundleutils/IkeSessionParamsUtils.java | 1 + .../vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 09f528369f..be57372193 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -79,6 +79,7 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); } /** Serializes an IkeSessionParams to a PersistableBundle. */ diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index f3851130c6..3b201f9d20 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -135,11 +135,12 @@ public class IkeSessionParamsUtilsTest { } @Test - public void testEncodeRecodeParamsWithIkeOptions() throws Exception { + public void testEncodeDecodeParamsWithIkeOptions() throws Exception { final IkeSessionParams params = createBuilderMinimum() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } From 410b0335ed85af63c2555a8b8a7ed829d398aa74 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 1 Nov 2021 22:56:53 +0800 Subject: [PATCH 0279/1057] Set underlying network of VCN VCN has already known its underlying network, so set it into NetworkCapabilities directly. Bug: 191918368 Test: atest FrameworksVcnTests Change-Id: Ibfe4f12bc5f3a8b7679d8a2c3b1b2f2161b9c9e5 --- .../src/com/android/server/vcn/VcnGatewayConnection.java | 3 +-- .../server/vcn/VcnGatewayConnectionConnectedStateTest.java | 3 +-- .../com/android/server/vcn/VcnGatewayConnectionTest.java | 5 ++++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 7dec4e785f..239a916fc5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1663,8 +1663,6 @@ public class VcnGatewayConnection extends StateMachine { } /* validationStatusCallback */); agent.register(); - agent.setUnderlyingNetworks( - mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); agent.markConnected(); return agent; @@ -2039,6 +2037,7 @@ public class VcnGatewayConnection extends StateMachine { "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + " non-null underlying network"); } + builder.setUnderlyingNetworks(List.of(underlying.network)); } else { Slog.wtf( TAG, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index c9a8947ab5..937f9dc60a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -297,8 +297,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any()); verify(mNetworkAgent).register(); - verify(mNetworkAgent) - .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network))); verify(mNetworkAgent).markConnected(); verify(mIpSecSvc) @@ -313,6 +311,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection final NetworkCapabilities nc = ncCaptor.getValue(); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + assertEquals(List.of(TEST_UNDERLYING_NETWORK_RECORD_1.network), nc.getUnderlyingNetworks()); for (int cap : mConfig.getAllExposedCapabilities()) { assertTrue(nc.hasCapability(cap)); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a700171353..5253c3e9b7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -61,6 +61,7 @@ import org.junit.runner.RunWith; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -116,8 +117,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH); capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); + final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS); UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( - mock(Network.class, CALLS_REAL_METHODS), + underlyingNetwork, capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( @@ -128,6 +130,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(vcnCaps.getUnderlyingNetworks().equals(List.of(underlyingNetwork))); for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) { From fdade1ff78920e2e900e39de2768c091ca3c391e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 1 Nov 2021 22:26:56 +0000 Subject: [PATCH 0280/1057] Pull underlying network MTU using Java APIs This change ensures that if the VCN's underlying network MTU is not reported via the LinkProperties APIs (as in the case of Carrier WiFi), the kernel values will be used (as possible). Bug: 204813618 Test: Manual testing Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: If291aa6b915e4da39152a679bbe3e40216b42f44 --- .../server/vcn/VcnGatewayConnection.java | 22 +++++- .../server/vcn/VcnGatewayConnectionTest.java | 70 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 7dec4e785f..3ef906929a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -98,6 +98,7 @@ import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -2049,7 +2050,8 @@ public class VcnGatewayConnection extends StateMachine { return builder.build(); } - private static LinkProperties buildConnectedLinkProperties( + @VisibleForTesting(visibility = Visibility.PRIVATE) + LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @@ -2077,6 +2079,13 @@ public class VcnGatewayConnection extends StateMachine { lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); underlyingMtu = underlyingLp.getMtu(); + + // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result + // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by + // NetworkInterface APIs. + if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) { + underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName()); + } } else { Slog.wtf( TAG, @@ -2418,6 +2427,17 @@ public class VcnGatewayConnection extends StateMachine { public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); } + + /** Gets the MTU for the given underlying interface. */ + public int getUnderlyingIfaceMtu(String ifaceName) { + try { + final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName); + return underlyingIface == null ? 0 : underlyingIface.getMTU(); + } catch (IOException e) { + Slog.d(TAG, "Could not get MTU of underlying network", e); + return 0; + } + } } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a700171353..b8eefabea3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn; +import static android.net.IpSecManager.IpSecTunnelInterface; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -24,6 +25,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; @@ -36,8 +39,11 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.net.IpSecManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -59,8 +65,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.InetAddress; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -70,6 +79,8 @@ import java.util.UUID; public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid() + 1; + private static final String LOOPBACK_IFACE = "lo"; + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -77,6 +88,12 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map TEST_SUBID_TO_GROUP_MAP; + private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6"; + private static final int TEST_MTU = 1300; + private static final int TEST_MTU_DELTA = 64; + private static final List TEST_INTERNAL_ADDRESSES = + Arrays.asList(new LinkAddress(DUMMY_ADDR, 16)); + private static final List TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR); private static final int TEST_UPSTREAM_BANDWIDTH = 1234; private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; @@ -165,6 +182,59 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */); } + @Test + public void testBuildLinkProperties() throws Exception { + final IpSecTunnelInterface tunnelIface = + mContext.getSystemService(IpSecManager.class) + .createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); + + final LinkProperties underlyingLp = new LinkProperties(); + underlyingLp.setInterfaceName(LOOPBACK_IFACE); + underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES); + doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final VcnChildSessionConfiguration childSessionConfig = + mock(VcnChildSessionConfiguration.class); + doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses(); + doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers(); + + UnderlyingNetworkRecord record = + new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + new NetworkCapabilities.Builder().build(), + underlyingLp, + false); + + final LinkProperties vcnLp1 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + // Instead of having to recalculate the final MTU (after accounting for IPsec overhead), + // calculate another set of Link Properties with a lower MTU, and calculate the delta. + doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final LinkProperties vcnLp2 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName()); + assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses()); + assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes()); + assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu()); + } + @Test public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { verifyWakeLockSetUp(); From f1c413085c0169e6254e4ac532679a7f044cae04 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Thu, 28 Oct 2021 23:00:31 +0000 Subject: [PATCH 0281/1057] Add NET_CAPABILITY_INTERNET NetworkCapability for VcnManagerTest Fix: When wifi connected, cellNetworkCb.waitForAvailable() will return null. VcnManagerTest test case will fail and throw 'No cell network found' error. android.net.vcn.cts.VcnManagerTest#testVcnMigrationAfterNetworkDies android.net.vcn.cts.VcnManagerTest#testSetVcnConfigOnTestNetwork android.net.vcn.cts.VcnManagerTest#testVcnSafemodeOnTestNetwork Test: atest VcnManagerTest Bug: 203745087 Change-Id: I8e8195689a314583e6a926f1d73c9c44608a12ed Signed-off-by: Henry Zhuang Merged-In: I917dfe14149945398a39f8366b4b360b04970dab (cherry picked from commit ab85c4890a2755f0a96c199d0a8be87a652d32d9) --- .../android/net/vcn/cts/VcnManagerTest.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 33df59574d..9670611439 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -442,8 +442,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -563,8 +565,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); @@ -662,8 +666,10 @@ public class VcnManagerTest extends VcnTestBase { // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before // waiting for VCN Network. - final NetworkRequest cellNetworkReq = - new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); final Network cellNetwork = cellNetworkCb.waitForAvailable(); From 7505638da513cb615eef4f955e86a56c2e4cb878 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 15 Nov 2021 15:43:02 -0800 Subject: [PATCH 0282/1057] Rename UnderlyingNetworkTracker to UnderlyingNetworkController Bug: 206044122 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: I6b4888f8252999446a29076937d9695278ff6a66 --- .../android/server/VcnManagementService.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 48 +++++++------ .../UnderlyingNetworkController.java} | 39 +++++----- ...cnGatewayConnectionConnectedStateTest.java | 8 +-- ...nGatewayConnectionConnectingStateTest.java | 6 +- ...atewayConnectionDisconnectedStateTest.java | 4 +- ...atewayConnectionRetryTimeoutStateTest.java | 6 +- .../server/vcn/VcnGatewayConnectionTest.java | 10 +-- .../vcn/VcnGatewayConnectionTestBase.java | 11 +-- .../UnderlyingNetworkControllerTest.java} | 72 +++++++++---------- 10 files changed, 105 insertions(+), 101 deletions(-) rename Vcn/service-b/src/com/android/server/vcn/{UnderlyingNetworkTracker.java => routeselection/UnderlyingNetworkController.java} (96%) rename Vcn/tests/unit/java/com/android/server/vcn/{UnderlyingNetworkTrackerTest.java => routeselection/UnderlyingNetworkControllerTest.java} (87%) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index b068f86ff0..0c990ecfc8 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -141,7 +141,7 @@ import java.util.concurrent.TimeUnit; * | or its properties * v | * +-----------------------------------------------------------------------+ - * | UnderlyingNetworkTracker | + * | UnderlyingNetworkController | * | | * | Manages lifecycle of underlying physical networks, filing requests to | * | bring them up, and releasing them as they become no longer necessary | diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 1c46ac8c4a..886127c2b6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -87,9 +87,10 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkController; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; import com.android.server.vcn.util.OneWayBoolean; @@ -201,7 +202,7 @@ public class VcnGatewayConnection extends StateMachine { private interface EventInfo {} /** - * Sent when there are changes to the underlying network (per the UnderlyingNetworkTracker). + * Sent when there are changes to the underlying network (per the UnderlyingNetworkController). * *

      May indicate an entirely new underlying network, OR a change in network properties. * @@ -522,11 +523,14 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; - @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + @NonNull private final UnderlyingNetworkController mUnderlyingNetworkController; @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull private final Dependencies mDeps; - @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback; + + @NonNull + private final VcnUnderlyingNetworkControllerCallback mUnderlyingNetworkControllerCallback; + private final boolean mIsMobileDataEnabled; @NonNull private final IpSecManager mIpSecManager; @@ -674,17 +678,17 @@ public class VcnGatewayConnection extends StateMachine { mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); - mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback(); + mUnderlyingNetworkControllerCallback = new VcnUnderlyingNetworkControllerCallback(); mWakeLock = mDeps.newWakeLock(mVcnContext.getContext(), PowerManager.PARTIAL_WAKE_LOCK, TAG); - mUnderlyingNetworkTracker = - mDeps.newUnderlyingNetworkTracker( + mUnderlyingNetworkController = + mDeps.newUnderlyingNetworkController( mVcnContext, subscriptionGroup, mLastSnapshot, - mUnderlyingNetworkTrackerCallback); + mUnderlyingNetworkControllerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); addState(mDisconnectedState); @@ -748,7 +752,7 @@ public class VcnGatewayConnection extends StateMachine { cancelRetryTimeoutAlarm(); cancelSafeModeAlarm(); - mUnderlyingNetworkTracker.teardown(); + mUnderlyingNetworkController.teardown(); mGatewayStatusCallback.onQuit(); } @@ -764,12 +768,13 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.ensureRunningOnLooperThread(); mLastSnapshot = snapshot; - mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot); + mUnderlyingNetworkController.updateSubscriptionSnapshot(mLastSnapshot); sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); } - private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { + private class VcnUnderlyingNetworkControllerCallback + implements UnderlyingNetworkControllerCallback { @Override public void onSelectedUnderlyingNetworkChanged( @Nullable UnderlyingNetworkRecord underlying) { @@ -2264,7 +2269,7 @@ public class VcnGatewayConnection extends StateMachine { + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); pw.println(); - mUnderlyingNetworkTracker.dump(pw); + mUnderlyingNetworkController.dump(pw); pw.println(); pw.decreaseIndent(); @@ -2276,8 +2281,8 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() { - return mUnderlyingNetworkTrackerCallback; + UnderlyingNetworkControllerCallback getUnderlyingNetworkControllerCallback() { + return mUnderlyingNetworkControllerCallback; } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -2356,17 +2361,14 @@ public class VcnGatewayConnection extends StateMachine { /** External dependencies used by VcnGatewayConnection, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { - /** Builds a new UnderlyingNetworkTracker. */ - public UnderlyingNetworkTracker newUnderlyingNetworkTracker( + /** Builds a new UnderlyingNetworkController. */ + public UnderlyingNetworkController newUnderlyingNetworkController( VcnContext vcnContext, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkTrackerCallback callback) { - return new UnderlyingNetworkTracker( - vcnContext, - subscriptionGroup, - snapshot, - callback); + UnderlyingNetworkControllerCallback callback) { + return new UnderlyingNetworkController( + vcnContext, subscriptionGroup, snapshot, callback); } /** Builds a new IkeSession. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java similarity index 96% rename from Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java rename to Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 7ddd1355a2..b36d4fea3a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn; +package com.android.server.vcn.routeselection; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -48,6 +48,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; import java.util.ArrayList; import java.util.Collections; @@ -61,14 +62,14 @@ import java.util.TreeSet; /** * Tracks a set of Networks underpinning a VcnGatewayConnection. * - *

      A single UnderlyingNetworkTracker is built to serve a SINGLE VCN Gateway Connection, and MUST - * be torn down with the VcnGatewayConnection in order to ensure underlying networks are allowed to - * be reaped. + *

      A single UnderlyingNetworkController is built to serve a SINGLE VCN Gateway Connection, and + * MUST be torn down with the VcnGatewayConnection in order to ensure underlying networks are + * allowed to be reaped. * * @hide */ -public class UnderlyingNetworkTracker { - @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); +public class UnderlyingNetworkController { + @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName(); /** * Minimum signal strength for a WiFi network to be eligible for switching to @@ -122,7 +123,7 @@ public class UnderlyingNetworkTracker { @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; - @NonNull private final UnderlyingNetworkTrackerCallback mCb; + @NonNull private final UnderlyingNetworkControllerCallback mCb; @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; @@ -142,11 +143,11 @@ public class UnderlyingNetworkTracker { @Nullable private UnderlyingNetworkRecord mCurrentRecord; @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; - public UnderlyingNetworkTracker( + public UnderlyingNetworkController( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull UnderlyingNetworkTrackerCallback cb) { + @NonNull UnderlyingNetworkControllerCallback cb) { this( vcnContext, subscriptionGroup, @@ -155,11 +156,11 @@ public class UnderlyingNetworkTracker { new Dependencies()); } - private UnderlyingNetworkTracker( + private UnderlyingNetworkController( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull UnderlyingNetworkTrackerCallback cb, + @NonNull UnderlyingNetworkControllerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); @@ -271,8 +272,8 @@ public class UnderlyingNetworkTracker { * subscription group, while the VCN networks are excluded by virtue of not having subIds set on * the VCN-exposed networks. * - *

      If the VCN that this UnderlyingNetworkTracker belongs to is in test-mode, this will return - * a NetworkRequest that only matches Test Networks. + *

      If the VCN that this UnderlyingNetworkController belongs to is in test-mode, this will + * return a NetworkRequest that only matches Test Networks. */ private NetworkRequest getRouteSelectionRequest() { if (mVcnContext.isInTestMode()) { @@ -373,9 +374,9 @@ public class UnderlyingNetworkTracker { } /** - * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot. + * Update this UnderlyingNetworkController's TelephonySubscriptionSnapshot. * - *

      Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to + *

      Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkController to * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change. */ @@ -410,7 +411,7 @@ public class UnderlyingNetworkTracker { private void reevaluateNetworks() { if (mIsQuitting || mRouteSelectionCallback == null) { - return; // UnderlyingNetworkTracker has quit. + return; // UnderlyingNetworkController has quit. } TreeSet sorted = @@ -572,7 +573,7 @@ public class UnderlyingNetworkTracker { public final boolean isBlocked; @VisibleForTesting(visibility = Visibility.PRIVATE) - UnderlyingNetworkRecord( + public UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, @@ -780,7 +781,7 @@ public class UnderlyingNetworkTracker { /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { - pw.println("UnderlyingNetworkTracker:"); + pw.println("UnderlyingNetworkController:"); pw.increaseIndent(); pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig)); @@ -811,7 +812,7 @@ public class UnderlyingNetworkTracker { } /** Callbacks for being notified of the changes in, or to the selected underlying network. */ - public interface UnderlyingNetworkTrackerCallback { + public interface UnderlyingNetworkControllerCallback { /** * Fired when a new underlying network is selected, or properties have changed. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 937f9dc60a..15de226cdc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -119,7 +119,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testNullNetworkDoesNotTriggerDisconnect() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); @@ -131,7 +131,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testNewNetworkTriggersMigration() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); mTestLooper.dispatchAll(); @@ -143,7 +143,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testSameNetworkDoesNotTriggerMigration() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); mTestLooper.dispatchAll(); @@ -203,7 +203,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerChildOpened(); mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index d1f3a210d8..3c70759a2f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -64,7 +64,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio @Test public void testNullNetworkTriggersDisconnect() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); @@ -76,7 +76,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio @Test public void testNewNetworkTriggersReconnect() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); mTestLooper.dispatchAll(); @@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio @Test public void testSameNetworkDoesNotTriggerReconnect() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); mTestLooper.dispatchAll(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 2056eea42c..f3eb82f46d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -78,7 +78,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect @Test public void testNetworkChangesTriggerStateTransitions() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); mTestLooper.dispatchAll(); @@ -89,7 +89,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect @Test public void testNullNetworkDoesNotTriggerStateTransition() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 1c859790a2..6568cdd443 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -58,7 +58,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect @Test public void testNewNetworkTriggerRetry() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); mTestLooper.dispatchAll(); @@ -72,7 +72,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect @Test public void testSameNetworkDoesNotTriggerRetry() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); mTestLooper.dispatchAll(); @@ -86,7 +86,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect @Test public void testNullNetworkTriggersDisconnect() throws Exception { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); mTestLooper.dispatchAll(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 2b0037eaf8..2d4eca8b09 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -59,7 +59,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import org.junit.Before; import org.junit.Test; @@ -238,14 +238,14 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } @Test - public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { + public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkController() { verifyWakeLockSetUp(); final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot); - verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot)); + verify(mUnderlyingNetworkController).updateSubscriptionSnapshot(eq(updatedSnapshot)); verifyWakeLockAcquired(); mTestLooper.dispatchAll(); @@ -256,13 +256,13 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { @Test public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() { mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); mGatewayConnection - .getUnderlyingNetworkTrackerCallback() + .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); verify(mDisconnectRequestAlarm).cancel(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 64d0bca15c..0db9830ce4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -16,10 +16,10 @@ package com.android.server.vcn; -import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; +import static com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -62,6 +62,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock; +import com.android.server.vcn.routeselection.UnderlyingNetworkController; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -137,7 +138,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final VcnGatewayConnectionConfig mConfig; @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback; @NonNull protected final VcnGatewayConnection.Dependencies mDeps; - @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + @NonNull protected final UnderlyingNetworkController mUnderlyingNetworkController; @NonNull protected final VcnWakeLock mWakeLock; @NonNull protected final WakeupMessage mTeardownTimeoutAlarm; @NonNull protected final WakeupMessage mDisconnectRequestAlarm; @@ -158,7 +159,7 @@ public class VcnGatewayConnectionTestBase { mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class); mDeps = mock(VcnGatewayConnection.Dependencies.class); - mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); + mUnderlyingNetworkController = mock(UnderlyingNetworkController.class); mWakeLock = mock(VcnWakeLock.class); mTeardownTimeoutAlarm = mock(WakeupMessage.class); mDisconnectRequestAlarm = mock(WakeupMessage.class); @@ -176,9 +177,9 @@ public class VcnGatewayConnectionTestBase { doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); - doReturn(mUnderlyingNetworkTracker) + doReturn(mUnderlyingNetworkController) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any(), any()); + .newUnderlyingNetworkController(any(), any(), any(), any()); doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java similarity index 87% rename from Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java rename to Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 5af69b5d1b..5b9544e3be 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn; +package com.android.server.vcn.routeselection; import static com.android.server.vcn.VcnTestUtils.setupSystemService; @@ -48,10 +48,12 @@ import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; -import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; +import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import org.junit.Before; import org.junit.Test; @@ -64,7 +66,7 @@ import java.util.Arrays; import java.util.Set; import java.util.UUID; -public class UnderlyingNetworkTrackerTest { +public class UnderlyingNetworkControllerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int INITIAL_SUB_ID_1 = 1; private static final int INITIAL_SUB_ID_2 = 2; @@ -102,14 +104,14 @@ public class UnderlyingNetworkTrackerTest { @Mock private TelephonyManager mTelephonyManager; @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; - @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; + @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb; @Mock private Network mNetwork; @Captor private ArgumentCaptor mUnderlyingNetworkListenerCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; - private UnderlyingNetworkTracker mUnderlyingNetworkTracker; + private UnderlyingNetworkController mUnderlyingNetworkController; @Before public void setUp() { @@ -140,12 +142,9 @@ public class UnderlyingNetworkTrackerTest { when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); - mUnderlyingNetworkTracker = - new UnderlyingNetworkTracker( - mVcnContext, - SUB_GROUP, - mSubscriptionSnapshot, - mNetworkTrackerCb); + mUnderlyingNetworkController = + new UnderlyingNetworkController( + mVcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb); } private void resetVcnContext() { @@ -181,11 +180,8 @@ public class UnderlyingNetworkTrackerTest { mVcnNetworkProvider, true /* isInTestMode */); - new UnderlyingNetworkTracker( - vcnContext, - SUB_GROUP, - mSubscriptionSnapshot, - mNetworkTrackerCb); + new UnderlyingNetworkController( + vcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb); verify(cm) .registerNetworkCallback( @@ -233,7 +229,7 @@ public class UnderlyingNetworkTrackerTest { mock(TelephonySubscriptionSnapshot.class); when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS); - mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); + mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate); // verify that initially-filed bringup requests are unregistered (cell + wifi) verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3)) @@ -255,7 +251,7 @@ public class UnderlyingNetworkTrackerTest { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setSubscriptionIds(netCapsSubIds) - .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) + .setSignalStrength(UnderlyingNetworkController.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) .build(); } @@ -264,7 +260,7 @@ public class UnderlyingNetworkTrackerTest { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setSubscriptionIds(netCapsSubIds) - .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) + .setSignalStrength(UnderlyingNetworkController.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) .build(); } @@ -304,7 +300,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testTeardown() { - mUnderlyingNetworkTracker.teardown(); + mUnderlyingNetworkController.teardown(); // Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for // each subId), and 1 for each of the Wifi signal strength thresholds @@ -368,7 +364,7 @@ public class UnderlyingNetworkTrackerTest { networkCapabilities, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); return cb; } @@ -384,7 +380,7 @@ public class UnderlyingNetworkTrackerTest { UPDATED_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -399,7 +395,7 @@ public class UnderlyingNetworkTrackerTest { INITIAL_NETWORK_CAPABILITIES, UPDATED_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -414,11 +410,13 @@ public class UnderlyingNetworkTrackerTest { SUSPENDED_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb, times(1)) + .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); - verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb, times(1)) + .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -434,11 +432,13 @@ public class UnderlyingNetworkTrackerTest { INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb, times(1)) + .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); - verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb, times(1)) + .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -453,7 +453,7 @@ public class UnderlyingNetworkTrackerTest { INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, true /* isBlocked */); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @Test @@ -462,7 +462,7 @@ public class UnderlyingNetworkTrackerTest { cb.onLost(mNetwork); - verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); } @Test @@ -471,20 +471,20 @@ public class UnderlyingNetworkTrackerTest { cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); - // Verify no more calls to the UnderlyingNetworkTrackerCallback when the + // Verify no more calls to the UnderlyingNetworkControllerCallback when the // UnderlyingNetworkRecord does not actually change - verifyNoMoreInteractions(mNetworkTrackerCb); + verifyNoMoreInteractions(mNetworkControllerCb); } @Test public void testRecordTrackerCallbackNotifiedAfterTeardown() { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); - mUnderlyingNetworkTracker.teardown(); + mUnderlyingNetworkController.teardown(); cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); // Verify that the only call was during onAvailable() - verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); + verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); } // TODO (b/187991063): Add tests for network prioritization From 2be314fc4784cb63166a71a5262de74264d6a502 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 22 Nov 2021 15:26:38 -0800 Subject: [PATCH 0283/1057] Split out NetworkPriorityClassifier and UnderlyingNetworkRecord Move UnderlyingNetworkRecord to a spearate file, and move calculatePriorityClass to a new class NetworkPriorityClassifier. This is a preparation CL to support vcn routeselection with configurable network priority classes and network metric monitors. Bug: 206044122 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: I88aa9e8dcf01524ddce9f913f40a4c712f8c878d --- .../server/vcn/VcnGatewayConnection.java | 2 +- .../NetworkPriorityClassifier.java | 196 ++++++++++++ .../UnderlyingNetworkController.java | 300 +----------------- .../UnderlyingNetworkRecord.java | 175 ++++++++++ .../server/vcn/VcnGatewayConnectionTest.java | 2 +- .../vcn/VcnGatewayConnectionTestBase.java | 2 +- .../UnderlyingNetworkControllerTest.java | 7 +- 7 files changed, 381 insertions(+), 303 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java create mode 100644 Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 886127c2b6..be13168815 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -90,7 +90,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; -import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; +import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; import com.android.server.vcn.util.OneWayBoolean; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java new file mode 100644 index 0000000000..bea8ae932a --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -0,0 +1,196 @@ +/* + * 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.server.vcn.routeselection; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.server.VcnManagementService.LOCAL_LOG; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnManager; +import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.SubscriptionManager; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; + +import java.util.Set; + +/** @hide */ +class NetworkPriorityClassifier { + @NonNull private static final String TAG = NetworkPriorityClassifier.class.getSimpleName(); + /** + * Minimum signal strength for a WiFi network to be eligible for switching to + * + *

      A network that satisfies this is eligible to become the selected underlying network with + * no additional conditions + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70; + /** + * Minimum signal strength to continue using a WiFi network + * + *

      A network that satisfies the conditions may ONLY continue to be used if it is already + * selected as the underlying network. A WiFi network satisfying this condition, but NOT the + * prospective-network RSSI threshold CANNOT be switched to. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; + /** Priority for any cellular network for which the subscription is listed as opportunistic */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0; + /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_IN_USE = 1; + /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_PROSPECTIVE = 2; + /** Priority for any standard macro cellular network */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_MACRO_CELLULAR = 3; + /** Priority for any other networks (including unvalidated, etc) */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_ANY = Integer.MAX_VALUE; + + private static final SparseArray PRIORITY_TO_STRING_MAP = new SparseArray<>(); + + static { + PRIORITY_TO_STRING_MAP.put( + PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR"); + PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY"); + } + + /** + * Gives networks a priority class, based on the following priorities: + * + *

        + *
      1. Opportunistic cellular + *
      2. Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT + *
      3. Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT + *
      4. Macro cellular + *
      5. Any others + *
      + */ + static int calculatePriorityClass( + UnderlyingNetworkRecord networkRecord, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkRecord.networkCapabilities; + + // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED + + if (networkRecord.isBlocked) { + logWtf("Network blocked for System Server: " + networkRecord.network); + return PRIORITY_ANY; + } + + if (caps.hasTransport(TRANSPORT_CELLULAR) + && isOpportunistic(snapshot, caps.getSubscriptionIds())) { + // If this carrier is the active data provider, ensure that opportunistic is only + // ever prioritized if it is also the active data subscription. This ensures that + // if an opportunistic subscription is still in the process of being switched to, + // or switched away from, the VCN does not attempt to continue using it against the + // decision made at the telephony layer. Failure to do so may result in the modem + // switching back and forth. + // + // Allow the following two cases: + // 1. Active subId is NOT in the group that this VCN is supporting + // 2. This opportunistic subscription is for the active subId + if (!snapshot.getAllSubIdsInGroup(subscriptionGroup) + .contains(SubscriptionManager.getActiveDataSubscriptionId()) + || caps.getSubscriptionIds() + .contains(SubscriptionManager.getActiveDataSubscriptionId())) { + return PRIORITY_OPPORTUNISTIC_CELLULAR; + } + } + + if (caps.hasTransport(TRANSPORT_WIFI)) { + if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) + && currentlySelected != null + && networkRecord.network.equals(currentlySelected.network)) { + return PRIORITY_WIFI_IN_USE; + } + + if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { + return PRIORITY_WIFI_PROSPECTIVE; + } + } + + // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might + // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be + // the case if the Default Data SubId does not support certain services (eg voice + // calling) + if (caps.hasTransport(TRANSPORT_CELLULAR) + && !isOpportunistic(snapshot, caps.getSubscriptionIds())) { + return PRIORITY_MACRO_CELLULAR; + } + + return PRIORITY_ANY; + } + + static boolean isOpportunistic( + @NonNull TelephonySubscriptionSnapshot snapshot, Set subIds) { + if (snapshot == null) { + logWtf("Got null snapshot"); + return false; + } + for (int subId : subIds) { + if (snapshot.isOpportunistic(subId)) { + return true; + } + } + return false; + } + + static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT); + } + return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; + } + + static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + WIFI_EXIT_RSSI_THRESHOLD_DEFAULT); + } + return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; + } + + static String priorityClassToString(int priorityClass) { + return PRIORITY_TO_STRING_MAP.get(priorityClass, "unknown"); + } + + private static void logWtf(String msg) { + Slog.wtf(TAG, msg); + LOCAL_LOG.log(TAG + " WTF: " + msg); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index b36d4fea3a..071c7a683c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -16,11 +16,12 @@ package com.android.server.vcn.routeselection; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.VcnManagementService.LOCAL_LOG; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.isOpportunistic; import android.annotation.NonNull; import android.annotation.Nullable; @@ -31,28 +32,23 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; -import android.net.vcn.VcnManager; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Slog; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -71,56 +67,6 @@ import java.util.TreeSet; public class UnderlyingNetworkController { @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName(); - /** - * Minimum signal strength for a WiFi network to be eligible for switching to - * - *

      A network that satisfies this is eligible to become the selected underlying network with - * no additional conditions - */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70; - - /** - * Minimum signal strength to continue using a WiFi network - * - *

      A network that satisfies the conditions may ONLY continue to be used if it is already - * selected as the underlying network. A WiFi network satisfying this condition, but NOT the - * prospective-network RSSI threshold CANNOT be switched to. - */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; - - /** Priority for any cellular network for which the subscription is listed as opportunistic */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0; - - /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_WIFI_IN_USE = 1; - - /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_WIFI_PROSPECTIVE = 2; - - /** Priority for any standard macro cellular network */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_MACRO_CELLULAR = 3; - - /** Priority for any other networks (including unvalidated, etc) */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_ANY = Integer.MAX_VALUE; - - private static final SparseArray PRIORITY_TO_STRING_MAP = new SparseArray<>(); - - static { - PRIORITY_TO_STRING_MAP.put( - PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY"); - } - @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkControllerCallback mCb; @@ -425,22 +371,6 @@ public class UnderlyingNetworkController { mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); } - private static boolean isOpportunistic( - @NonNull TelephonySubscriptionSnapshot snapshot, Set subIds) { - if (snapshot == null) { - logWtf("Got null snapshot"); - return false; - } - - for (int subId : subIds) { - if (snapshot.isOpportunistic(subId)) { - return true; - } - } - - return false; - } - /** * NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped. * @@ -545,230 +475,6 @@ public class UnderlyingNetworkController { } } - private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { - if (carrierConfig != null) { - return carrierConfig.getInt( - VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, - WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT); - } - - return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; - } - - private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { - if (carrierConfig != null) { - return carrierConfig.getInt( - VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, - WIFI_EXIT_RSSI_THRESHOLD_DEFAULT); - } - - return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; - } - - /** A record of a single underlying network, caching relevant fields. */ - public static class UnderlyingNetworkRecord { - @NonNull public final Network network; - @NonNull public final NetworkCapabilities networkCapabilities; - @NonNull public final LinkProperties linkProperties; - public final boolean isBlocked; - - @VisibleForTesting(visibility = Visibility.PRIVATE) - public UnderlyingNetworkRecord( - @NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, - boolean isBlocked) { - this.network = network; - this.networkCapabilities = networkCapabilities; - this.linkProperties = linkProperties; - this.isBlocked = isBlocked; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof UnderlyingNetworkRecord)) return false; - final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o; - - return network.equals(that.network) - && networkCapabilities.equals(that.networkCapabilities) - && linkProperties.equals(that.linkProperties) - && isBlocked == that.isBlocked; - } - - @Override - public int hashCode() { - return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); - } - - /** - * Gives networks a priority class, based on the following priorities: - * - *

        - *
      1. Opportunistic cellular - *
      2. Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT - *
      3. Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT - *
      4. Macro cellular - *
      5. Any others - *
      - */ - private int calculatePriorityClass( - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { - final NetworkCapabilities caps = networkCapabilities; - - // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED - - if (isBlocked) { - logWtf("Network blocked for System Server: " + network); - return PRIORITY_ANY; - } - - if (caps.hasTransport(TRANSPORT_CELLULAR) - && isOpportunistic(snapshot, caps.getSubscriptionIds())) { - // If this carrier is the active data provider, ensure that opportunistic is only - // ever prioritized if it is also the active data subscription. This ensures that - // if an opportunistic subscription is still in the process of being switched to, - // or switched away from, the VCN does not attempt to continue using it against the - // decision made at the telephony layer. Failure to do so may result in the modem - // switching back and forth. - // - // Allow the following two cases: - // 1. Active subId is NOT in the group that this VCN is supporting - // 2. This opportunistic subscription is for the active subId - if (!snapshot.getAllSubIdsInGroup(subscriptionGroup) - .contains(SubscriptionManager.getActiveDataSubscriptionId()) - || caps.getSubscriptionIds() - .contains(SubscriptionManager.getActiveDataSubscriptionId())) { - return PRIORITY_OPPORTUNISTIC_CELLULAR; - } - } - - if (caps.hasTransport(TRANSPORT_WIFI)) { - if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) - && currentlySelected != null - && network.equals(currentlySelected.network)) { - return PRIORITY_WIFI_IN_USE; - } - - if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { - return PRIORITY_WIFI_PROSPECTIVE; - } - } - - // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might - // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be - // the case if the Default Data SubId does not support certain services (eg voice - // calling) - if (caps.hasTransport(TRANSPORT_CELLULAR) - && !isOpportunistic(snapshot, caps.getSubscriptionIds())) { - return PRIORITY_MACRO_CELLULAR; - } - - return PRIORITY_ANY; - } - - private static Comparator getComparator( - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { - return (left, right) -> { - return Integer.compare( - left.calculatePriorityClass( - subscriptionGroup, snapshot, currentlySelected, carrierConfig), - right.calculatePriorityClass( - subscriptionGroup, snapshot, currentlySelected, carrierConfig)); - }; - } - - /** Dumps the state of this record for logging and debugging purposes. */ - private void dump( - IndentingPrintWriter pw, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { - pw.println("UnderlyingNetworkRecord:"); - pw.increaseIndent(); - - final int priorityClass = - calculatePriorityClass( - subscriptionGroup, snapshot, currentlySelected, carrierConfig); - pw.println( - "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " (" - + priorityClass + ")"); - pw.println("mNetwork: " + network); - pw.println("mNetworkCapabilities: " + networkCapabilities); - pw.println("mLinkProperties: " + linkProperties); - - pw.decreaseIndent(); - } - - /** Builder to incrementally construct an UnderlyingNetworkRecord. */ - private static class Builder { - @NonNull private final Network mNetwork; - - @Nullable private NetworkCapabilities mNetworkCapabilities; - @Nullable private LinkProperties mLinkProperties; - boolean mIsBlocked; - boolean mWasIsBlockedSet; - - @Nullable private UnderlyingNetworkRecord mCached; - - private Builder(@NonNull Network network) { - mNetwork = network; - } - - @NonNull - private Network getNetwork() { - return mNetwork; - } - - private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { - mNetworkCapabilities = networkCapabilities; - mCached = null; - } - - @Nullable - private NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities; - } - - private void setLinkProperties(@NonNull LinkProperties linkProperties) { - mLinkProperties = linkProperties; - mCached = null; - } - - private void setIsBlocked(boolean isBlocked) { - mIsBlocked = isBlocked; - mWasIsBlockedSet = true; - mCached = null; - } - - private boolean isValid() { - return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; - } - - private UnderlyingNetworkRecord build() { - if (!isValid()) { - throw new IllegalArgumentException( - "Called build before UnderlyingNetworkRecord was valid"); - } - - if (mCached == null) { - mCached = - new UnderlyingNetworkRecord( - mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); - } - - return mCached; - } - } - } - private static void logWtf(String msg) { Slog.wtf(TAG, msg); LOCAL_LOG.log(TAG + " WTF: " + msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java new file mode 100644 index 0000000000..65c69dedcb --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -0,0 +1,175 @@ +/* + * 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.server.vcn.routeselection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.os.ParcelUuid; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; + +import java.util.Comparator; +import java.util.Objects; + +/** + * A record of a single underlying network, caching relevant fields. + * + * @hide + */ +public class UnderlyingNetworkRecord { + @NonNull public final Network network; + @NonNull public final NetworkCapabilities networkCapabilities; + @NonNull public final LinkProperties linkProperties; + public final boolean isBlocked; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public UnderlyingNetworkRecord( + @NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, + boolean isBlocked) { + this.network = network; + this.networkCapabilities = networkCapabilities; + this.linkProperties = linkProperties; + this.isBlocked = isBlocked; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UnderlyingNetworkRecord)) return false; + final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o; + + return network.equals(that.network) + && networkCapabilities.equals(that.networkCapabilities) + && linkProperties.equals(that.linkProperties) + && isBlocked == that.isBlocked; + } + + @Override + public int hashCode() { + return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); + } + + static Comparator getComparator( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + return (left, right) -> { + return Integer.compare( + NetworkPriorityClassifier.calculatePriorityClass( + left, subscriptionGroup, snapshot, currentlySelected, carrierConfig), + NetworkPriorityClassifier.calculatePriorityClass( + right, subscriptionGroup, snapshot, currentlySelected, carrierConfig)); + }; + } + + /** Dumps the state of this record for logging and debugging purposes. */ + void dump( + IndentingPrintWriter pw, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + pw.println("UnderlyingNetworkRecord:"); + pw.increaseIndent(); + + final int priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + this, subscriptionGroup, snapshot, currentlySelected, carrierConfig); + pw.println( + "Priority class: " + + NetworkPriorityClassifier.priorityClassToString(priorityClass) + + " (" + + priorityClass + + ")"); + pw.println("mNetwork: " + network); + pw.println("mNetworkCapabilities: " + networkCapabilities); + pw.println("mLinkProperties: " + linkProperties); + + pw.decreaseIndent(); + } + + /** Builder to incrementally construct an UnderlyingNetworkRecord. */ + static class Builder { + @NonNull private final Network mNetwork; + + @Nullable private NetworkCapabilities mNetworkCapabilities; + @Nullable private LinkProperties mLinkProperties; + boolean mIsBlocked; + boolean mWasIsBlockedSet; + + @Nullable private UnderlyingNetworkRecord mCached; + + Builder(@NonNull Network network) { + mNetwork = network; + } + + @NonNull + Network getNetwork() { + return mNetwork; + } + + void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + mNetworkCapabilities = networkCapabilities; + mCached = null; + } + + @Nullable + NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + void setLinkProperties(@NonNull LinkProperties linkProperties) { + mLinkProperties = linkProperties; + mCached = null; + } + + void setIsBlocked(boolean isBlocked) { + mIsBlocked = isBlocked; + mWasIsBlockedSet = true; + mCached = null; + } + + boolean isValid() { + return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; + } + + UnderlyingNetworkRecord build() { + if (!isValid()) { + throw new IllegalArgumentException( + "Called build before UnderlyingNetworkRecord was valid"); + } + + if (mCached == null) { + mCached = + new UnderlyingNetworkRecord( + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + } + + return mCached; + } + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 2d4eca8b09..b9dfda38a0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -59,7 +59,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; +import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import org.junit.Before; import org.junit.Test; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 0db9830ce4..8a0af2dff8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -19,7 +19,6 @@ package com.android.server.vcn; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; -import static com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -63,6 +62,7 @@ import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock; import com.android.server.vcn.routeselection.UnderlyingNetworkController; +import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import org.junit.Before; import org.mockito.ArgumentCaptor; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 5b9544e3be..c954cb84df 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -17,6 +17,8 @@ package com.android.server.vcn.routeselection; import static com.android.server.vcn.VcnTestUtils.setupSystemService; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -53,7 +55,6 @@ import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; -import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkRecord; import org.junit.Before; import org.junit.Test; @@ -251,7 +252,7 @@ public class UnderlyingNetworkControllerTest { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setSubscriptionIds(netCapsSubIds) - .setSignalStrength(UnderlyingNetworkController.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) + .setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) .build(); } @@ -260,7 +261,7 @@ public class UnderlyingNetworkControllerTest { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setSubscriptionIds(netCapsSubIds) - .setSignalStrength(UnderlyingNetworkController.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) + .setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) .build(); } From 3e8cef3237bdd905b9ce9c079c69f89a9a0f1efa Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Nov 2021 11:04:24 -0800 Subject: [PATCH 0284/1057] Create VcnUnderlyingNetworkPriority and the subclass for Wifi Create VcnUnderlyingNetworkPriority and VcnWifiUnderlyingNetworkPriority to allow VCN callers to configure network prioritization. Bug: 206044122 Test: atest FrameworksVcnTests(new tests) Test: atest CtsVcnTestCases Change-Id: I540f826176c7085780be93e42fdbc3ff0ad537d7 --- .../net/vcn/VcnUnderlyingNetworkPriority.java | 181 ++++++++++++++++++ .../vcn/VcnWifiUnderlyingNetworkPriority.java | 120 ++++++++++++ .../VcnWifiUnderlyingNetworkPriorityTest.java | 76 ++++++++ 3 files changed, 377 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java new file mode 100644 index 0000000000..27750c659f --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java @@ -0,0 +1,181 @@ +/* + * 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 android.net.vcn; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +// TODO: Add documents +/** @hide */ +public abstract class VcnUnderlyingNetworkPriority { + /** @hide */ + protected static final int NETWORK_PRIORITY_TYPE_WIFI = 1; + /** @hide */ + protected static final int NETWORK_PRIORITY_TYPE_CELL = 2; + + /** Denotes that network quality needs to be OK */ + public static final int NETWORK_QUALITY_OK = 10000; + /** Denotes that any network quality is acceptable */ + public static final int NETWORK_QUALITY_ANY = Integer.MAX_VALUE; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY}) + public @interface NetworkQuality {} + + private static final String NETWORK_PRIORITY_TYPE_KEY = "mNetworkPriorityType"; + private final int mNetworkPriorityType; + + /** @hide */ + protected static final String NETWORK_QUALITY_KEY = "mNetworkQuality"; + private final int mNetworkQuality; + + /** @hide */ + protected static final String ALLOW_METERED_KEY = "mAllowMetered"; + private final boolean mAllowMetered; + + /** @hide */ + protected VcnUnderlyingNetworkPriority( + int networkPriorityType, int networkQuality, boolean allowMetered) { + mNetworkPriorityType = networkPriorityType; + mNetworkQuality = networkQuality; + mAllowMetered = allowMetered; + } + + private static void validateNetworkQuality(int networkQuality) { + Preconditions.checkArgument( + networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK, + "Invalid networkQuality:" + networkQuality); + } + + /** @hide */ + protected void validate() { + validateNetworkQuality(mNetworkQuality); + } + + /** @hide */ + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public static VcnUnderlyingNetworkPriority fromPersistableBundle( + @NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle is null"); + + final int networkPriorityType = in.getInt(NETWORK_PRIORITY_TYPE_KEY); + switch (networkPriorityType) { + case NETWORK_PRIORITY_TYPE_WIFI: + return VcnWifiUnderlyingNetworkPriority.fromPersistableBundle(in); + case NETWORK_PRIORITY_TYPE_CELL: + throw new UnsupportedOperationException("Not implemented"); + default: + throw new IllegalArgumentException( + "Invalid networkPriorityType:" + networkPriorityType); + } + } + + /** @hide */ + @NonNull + PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType); + result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality); + result.putBoolean(ALLOW_METERED_KEY, mAllowMetered); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash(mNetworkPriorityType, mNetworkQuality, mAllowMetered); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof VcnUnderlyingNetworkPriority)) { + return false; + } + + final VcnUnderlyingNetworkPriority rhs = (VcnUnderlyingNetworkPriority) other; + return mNetworkPriorityType == rhs.mNetworkPriorityType + && mNetworkQuality == rhs.mNetworkQuality + && mAllowMetered == rhs.mAllowMetered; + } + + /** Retrieve the required network quality. */ + @NetworkQuality + public int getNetworkQuality() { + return mNetworkQuality; + } + + /** Return if a metered network is allowed. */ + public boolean allowMetered() { + return mAllowMetered; + } + + /** + * This class is used to incrementally build VcnUnderlyingNetworkPriority objects. + * + * @param The subclass to be built. + */ + public abstract static class Builder> { + /** @hide */ + protected int mNetworkQuality = NETWORK_QUALITY_ANY; + /** @hide */ + protected boolean mAllowMetered = false; + + /** @hide */ + protected Builder() {} + + /** + * Set the required network quality. + * + * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY + */ + @NonNull + public T setNetworkQuality(@NetworkQuality int networkQuality) { + validateNetworkQuality(networkQuality); + + mNetworkQuality = networkQuality; + return self(); + } + + /** + * Set if a metered network is allowed. + * + * @param allowMetered the flag to indicate if a metered network is allowed, defaults to + * {@code false} + */ + @NonNull + public T setAllowMetered(boolean allowMetered) { + mAllowMetered = allowMetered; + return self(); + } + + /** @hide */ + abstract T self(); + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java new file mode 100644 index 0000000000..fc7e7e2c4e --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java @@ -0,0 +1,120 @@ +/* + * 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 android.net.vcn; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + +// TODO: Add documents +/** @hide */ +public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority { + private static final String SSID_KEY = "mSsid"; + @Nullable private final String mSsid; + + private VcnWifiUnderlyingNetworkPriority( + int networkQuality, boolean allowMetered, String ssid) { + super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, allowMetered); + mSsid = ssid; + + validate(); + } + + /** @hide */ + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public static VcnWifiUnderlyingNetworkPriority fromPersistableBundle( + @NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle is null"); + + final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); + final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY); + final String ssid = in.getString(SSID_KEY); + return new VcnWifiUnderlyingNetworkPriority(networkQuality, allowMetered, ssid); + } + + /** @hide */ + @Override + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = super.toPersistableBundle(); + result.putString(SSID_KEY, mSsid); + return result; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), mSsid); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!super.equals(other)) { + return false; + } + + if (!(other instanceof VcnWifiUnderlyingNetworkPriority)) { + return false; + } + + final VcnWifiUnderlyingNetworkPriority rhs = (VcnWifiUnderlyingNetworkPriority) other; + return mSsid == rhs.mSsid; + } + + /** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */ + @Nullable + public String getSsid() { + return mSsid; + } + + /** This class is used to incrementally build VcnWifiUnderlyingNetworkPriority objects. */ + public static class Builder extends VcnUnderlyingNetworkPriority.Builder { + @Nullable private String mSsid; + + /** Construct a Builder object. */ + public Builder() {} + + /** + * Set the required SSID. + * + * @param ssid the required SSID, or {@code null} if any SSID is acceptable. + */ + @NonNull + public Builder setSsid(@Nullable String ssid) { + mSsid = ssid; + return this; + } + + /** Build the VcnWifiUnderlyingNetworkPriority. */ + @NonNull + public VcnWifiUnderlyingNetworkPriority build() { + return new VcnWifiUnderlyingNetworkPriority(mNetworkQuality, mAllowMetered, mSsid); + } + + /** @hide */ + @Override + Builder self() { + return this; + } + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java new file mode 100644 index 0000000000..69ffeadbff --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java @@ -0,0 +1,76 @@ +/* + * 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 android.net.vcn; + +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; + +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 org.junit.Test; + +public class VcnWifiUnderlyingNetworkPriorityTest { + private static final String SSID = "TestWifi"; + private static final int INVALID_NETWORK_QUALITY = -1; + + private static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() { + return new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setSsid(SSID) + .build(); + } + + @Test + public void testBuilderAndGetters() { + final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); + assertTrue(networkPriority.allowMetered()); + assertEquals(SSID, networkPriority.getSsid()); + } + + @Test + public void testBuilderAndGettersForDefaultValues() { + final VcnWifiUnderlyingNetworkPriority networkPriority = + new VcnWifiUnderlyingNetworkPriority.Builder().build(); + assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); + assertFalse(networkPriority.allowMetered()); + assertNull(SSID, networkPriority.getSsid()); + } + + @Test + public void testBuildWithInvalidNetworkQuality() { + try { + new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(INVALID_NETWORK_QUALITY); + fail("Expected to fail due to the invalid network quality"); + } catch (Exception expected) { + } + } + + @Test + public void testPersistableBundle() { + final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + assertEquals( + networkPriority, + VcnUnderlyingNetworkPriority.fromPersistableBundle( + networkPriority.toPersistableBundle())); + } +} From 65b74b26340c9cd29b6d8c887c6534e1791978ba Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 23 Nov 2021 18:36:10 -0800 Subject: [PATCH 0285/1057] Create VcnCellUnderlyingNetworkPriority Create VcnCellUnderlyingNetworkPriority to allow VCN callers to configure network prioritization. Bug: 206044122 Test: atest FrameworksVcnTests(new tests) Test: atest CtsVcnTestCases Change-Id: Ia7f44c5f956ff75c39e20d9761f1bd5c987644ee --- .../vcn/VcnCellUnderlyingNetworkPriority.java | 291 ++++++++++++++++++ .../net/vcn/VcnUnderlyingNetworkPriority.java | 2 +- .../net/vcn/util/PersistableBundleUtils.java | 16 + .../VcnCellUnderlyingNetworkPriorityTest.java | 76 +++++ 4 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java new file mode 100644 index 0000000000..6b33e4f45c --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java @@ -0,0 +1,291 @@ +/* + * 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 android.net.vcn; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; +import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; +import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; +import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; +import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.PersistableBundle; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +// TODO: Add documents +/** @hide */ +public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority { + private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds"; + @NonNull private final Set mAllowedNetworkPlmnIds; + private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds"; + @NonNull private final Set mAllowedSpecificCarrierIds; + + private static final String ALLOW_ROAMING_KEY = "mAllowRoaming"; + private final boolean mAllowRoaming; + + private static final String REQUIRE_OPPORTUNISTIC_KEY = "mRequireOpportunistic"; + private final boolean mRequireOpportunistic; + + private VcnCellUnderlyingNetworkPriority( + int networkQuality, + boolean allowMetered, + Set allowedNetworkPlmnIds, + Set allowedSpecificCarrierIds, + boolean allowRoaming, + boolean requireOpportunistic) { + super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, allowMetered); + mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds); + mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds); + mAllowRoaming = allowRoaming; + mRequireOpportunistic = requireOpportunistic; + + validate(); + } + + /** @hide */ + @Override + protected void validate() { + super.validate(); + validatePlmnIds(mAllowedNetworkPlmnIds); + Objects.requireNonNull(mAllowedSpecificCarrierIds, "allowedCarrierIds is null"); + } + + private static void validatePlmnIds(Set allowedNetworkPlmnIds) { + Objects.requireNonNull(allowedNetworkPlmnIds, "allowedNetworkPlmnIds is null"); + + // A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 decimal + // digits. + for (String id : allowedNetworkPlmnIds) { + if ((id.length() == 5 || id.length() == 6) && id.matches("[0-9]+")) { + continue; + } else { + throw new IllegalArgumentException("Found invalid PLMN ID: " + id); + } + } + } + + /** @hide */ + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public static VcnCellUnderlyingNetworkPriority fromPersistableBundle( + @NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle is null"); + + final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); + final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY); + + final PersistableBundle plmnIdsBundle = + in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY); + Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null"); + final Set allowedNetworkPlmnIds = + new ArraySet( + PersistableBundleUtils.toList(plmnIdsBundle, STRING_DESERIALIZER)); + + final PersistableBundle specificCarrierIdsBundle = + in.getPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY); + Objects.requireNonNull(specificCarrierIdsBundle, "specificCarrierIdsBundle is null"); + final Set allowedSpecificCarrierIds = + new ArraySet( + PersistableBundleUtils.toList( + specificCarrierIdsBundle, INTEGER_DESERIALIZER)); + + final boolean allowRoaming = in.getBoolean(ALLOW_ROAMING_KEY); + final boolean requireOpportunistic = in.getBoolean(REQUIRE_OPPORTUNISTIC_KEY); + + return new VcnCellUnderlyingNetworkPriority( + networkQuality, + allowMetered, + allowedNetworkPlmnIds, + allowedSpecificCarrierIds, + allowRoaming, + requireOpportunistic); + } + + /** @hide */ + @Override + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = super.toPersistableBundle(); + + final PersistableBundle plmnIdsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mAllowedNetworkPlmnIds), STRING_SERIALIZER); + result.putPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY, plmnIdsBundle); + + final PersistableBundle specificCarrierIdsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER); + result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle); + + result.putBoolean(ALLOW_ROAMING_KEY, mAllowRoaming); + result.putBoolean(REQUIRE_OPPORTUNISTIC_KEY, mRequireOpportunistic); + + return result; + } + + /** Retrieve the allowed PLMN IDs, or an empty set if any PLMN ID is acceptable. */ + @NonNull + public Set getAllowedPlmnIds() { + return Collections.unmodifiableSet(mAllowedNetworkPlmnIds); + } + + /** + * Retrieve the allowed specific carrier IDs, or an empty set if any specific carrier ID is + * acceptable. + */ + @NonNull + public Set getAllowedSpecificCarrierIds() { + return Collections.unmodifiableSet(mAllowedSpecificCarrierIds); + } + + /** Return if roaming is allowed. */ + public boolean allowRoaming() { + return mAllowRoaming; + } + + /** Return if requiring an opportunistic network. */ + public boolean requireOpportunistic() { + return mRequireOpportunistic; + } + + @Override + public int hashCode() { + return Objects.hash( + super.hashCode(), + mAllowedNetworkPlmnIds, + mAllowedSpecificCarrierIds, + mAllowRoaming, + mRequireOpportunistic); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!super.equals(other)) { + return false; + } + + if (!(other instanceof VcnCellUnderlyingNetworkPriority)) { + return false; + } + + final VcnCellUnderlyingNetworkPriority rhs = (VcnCellUnderlyingNetworkPriority) other; + return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds) + && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds) + && mAllowRoaming == rhs.mAllowRoaming + && mRequireOpportunistic == rhs.mRequireOpportunistic; + } + + /** This class is used to incrementally build WifiNetworkPriority objects. */ + public static class Builder extends VcnUnderlyingNetworkPriority.Builder { + @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); + @NonNull private final Set mAllowedSpecificCarrierIds = new ArraySet<>(); + + private boolean mAllowRoaming = false; + private boolean mRequireOpportunistic = false; + + /** Construct a Builder object. */ + public Builder() {} + + /** + * Set allowed operator PLMN IDs. + * + *

      This is used to distinguish cases where roaming agreements may dictate a different + * priority from a partner's networks. + * + * @param allowedNetworkPlmnIds the allowed operator PLMN IDs in String. Defaults to an + * empty set, allowing ANY PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and + * thus consists of 5 or 6 decimal digits. See {@link SubscriptionInfo#getMccString()} + * and {@link SubscriptionInfo#getMncString()}. + */ + @NonNull + public Builder setAllowedPlmnIds(@NonNull Set allowedNetworkPlmnIds) { + validatePlmnIds(allowedNetworkPlmnIds); + + mAllowedNetworkPlmnIds.clear(); + mAllowedNetworkPlmnIds.addAll(allowedNetworkPlmnIds); + return this; + } + + /** + * Set allowed specific carrier IDs. + * + * @param allowedSpecificCarrierIds the allowed specific carrier IDs. Defaults to an empty + * set, allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}. + */ + @NonNull + public Builder setAllowedSpecificCarrierIds( + @NonNull Set allowedSpecificCarrierIds) { + Objects.requireNonNull(allowedSpecificCarrierIds, "allowedCarrierIds is null"); + mAllowedSpecificCarrierIds.clear(); + mAllowedSpecificCarrierIds.addAll(allowedSpecificCarrierIds); + return this; + } + + /** + * Set if roaming is allowed. + * + * @param allowRoaming the flag to indicate if roaming is allowed. Defaults to {@code + * false}. + */ + @NonNull + public Builder setAllowRoaming(boolean allowRoaming) { + mAllowRoaming = allowRoaming; + return this; + } + + /** + * Set if requiring an opportunistic network. + * + * @param requireOpportunistic the flag to indicate if caller requires an opportunistic + * network. Defaults to {@code false}. + */ + @NonNull + public Builder setRequireOpportunistic(boolean requireOpportunistic) { + mRequireOpportunistic = requireOpportunistic; + return this; + } + + /** Build the VcnCellUnderlyingNetworkPriority. */ + @NonNull + public VcnCellUnderlyingNetworkPriority build() { + return new VcnCellUnderlyingNetworkPriority( + mNetworkQuality, + mAllowMetered, + mAllowedNetworkPlmnIds, + mAllowedSpecificCarrierIds, + mAllowRoaming, + mRequireOpportunistic); + } + + /** @hide */ + @Override + Builder self() { + return this; + } + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java index 27750c659f..82f6ae72b4 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java @@ -89,7 +89,7 @@ public abstract class VcnUnderlyingNetworkPriority { case NETWORK_PRIORITY_TYPE_WIFI: return VcnWifiUnderlyingNetworkPriority.fromPersistableBundle(in); case NETWORK_PRIORITY_TYPE_CELL: - throw new UnsupportedOperationException("Not implemented"); + return VcnCellUnderlyingNetworkPriority.fromPersistableBundle(in); default: throw new IllegalArgumentException( "Invalid networkPriorityType:" + networkPriorityType); diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 5c1b5ffb22..1c675c2285 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -46,6 +46,7 @@ public class PersistableBundleUtils { private static final String PARCEL_UUID_KEY = "PARCEL_UUID"; private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY"; private static final String INTEGER_KEY = "INTEGER_KEY"; + private static final String STRING_KEY = "STRING_KEY"; /** * Functional interface to convert an object of the specified type to a PersistableBundle. @@ -91,6 +92,21 @@ public class PersistableBundleUtils { return bundle.getInt(INTEGER_KEY); }; + /** Serializer to convert s String to a PersistableBundle. */ + public static final Serializer STRING_SERIALIZER = + (i) -> { + final PersistableBundle result = new PersistableBundle(); + result.putString(STRING_KEY, i); + return result; + }; + + /** Deserializer to convert a PersistableBundle to a String. */ + public static final Deserializer STRING_DESERIALIZER = + (bundle) -> { + Objects.requireNonNull(bundle, "PersistableBundle is null"); + return bundle.getString(STRING_KEY); + }; + /** * Converts a ParcelUuid to a PersistableBundle. * diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java new file mode 100644 index 0000000000..3e47eb1fa4 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java @@ -0,0 +1,76 @@ +/* + * 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 android.net.vcn; + +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +public class VcnCellUnderlyingNetworkPriorityTest { + private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); + private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); + + private static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() { + return new VcnCellUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setAllowedPlmnIds(ALLOWED_PLMN_IDS) + .setAllowedSpecificCarrierIds(ALLOWED_CARRIER_IDS) + .setAllowRoaming(true /* allowRoaming */) + .setRequireOpportunistic(true /* requireOpportunistic */) + .build(); + } + + @Test + public void testBuilderAndGetters() { + final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); + assertTrue(networkPriority.allowMetered()); + assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedPlmnIds()); + assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getAllowedSpecificCarrierIds()); + assertTrue(networkPriority.allowRoaming()); + assertTrue(networkPriority.requireOpportunistic()); + } + + @Test + public void testBuilderAndGettersForDefaultValues() { + final VcnCellUnderlyingNetworkPriority networkPriority = + new VcnCellUnderlyingNetworkPriority.Builder().build(); + assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); + assertFalse(networkPriority.allowMetered()); + assertEquals(new HashSet(), networkPriority.getAllowedPlmnIds()); + assertEquals(new HashSet(), networkPriority.getAllowedSpecificCarrierIds()); + assertFalse(networkPriority.allowRoaming()); + assertFalse(networkPriority.requireOpportunistic()); + } + + @Test + public void testPersistableBundle() { + final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + assertEquals( + networkPriority, + VcnUnderlyingNetworkPriority.fromPersistableBundle( + networkPriority.toPersistableBundle())); + } +} From 478ae37cf3b819cac41d734865c33199440f2df9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 24 Nov 2021 14:09:26 -0800 Subject: [PATCH 0286/1057] Support configuring VcnUnderlyingNetworkPriority in VcnGatwayConnectionConfig Bug: 206044122 Test: atest FrameworksVcnTests(new tests) Test: atest CtsVcnTestCases Change-Id: I5cd2982fcbfe5ce4ee36edb91f1f9f9b55d28d9a --- .../net/vcn/VcnGatewayConnectionConfig.java | 97 +++++++++++++++++++ .../VcnCellUnderlyingNetworkPriorityTest.java | 3 +- .../vcn/VcnGatewayConnectionConfigTest.java | 24 ++++- .../VcnWifiUnderlyingNetworkPriorityTest.java | 3 +- 4 files changed, 124 insertions(+), 3 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 752ef3e39a..de4ada2dbc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; import static com.android.internal.annotations.VisibleForTesting.Visibility; @@ -41,6 +42,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; import java.util.SortedSet; @@ -157,6 +159,34 @@ public final class VcnGatewayConnectionConfig { TimeUnit.MINUTES.toMillis(5), TimeUnit.MINUTES.toMillis(15) }; + + private static final LinkedHashSet + DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>(); + + static { + DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + new VcnCellUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setAllowRoaming(true /* allowRoaming */) + .setRequireOpportunistic(true /* requireOpportunistic */) + .build()); + + DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .build()); + + DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + new VcnCellUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setAllowRoaming(true /* allowRoaming */) + .setRequireOpportunistic(false /* requireOpportunistic */) + .build()); + } + private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName"; @NonNull private final String mGatewayConnectionName; @@ -166,6 +196,9 @@ public final class VcnGatewayConnectionConfig { private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; + private static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities"; + @NonNull private final LinkedHashSet mUnderlyingNetworkPriorities; + private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -177,6 +210,7 @@ public final class VcnGatewayConnectionConfig { @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, + @NonNull LinkedHashSet underlyingNetworkPriorities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; @@ -185,6 +219,11 @@ public final class VcnGatewayConnectionConfig { mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; + mUnderlyingNetworkPriorities = new LinkedHashSet<>(underlyingNetworkPriorities); + if (mUnderlyingNetworkPriorities.isEmpty()) { + mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + } + validate(); } @@ -198,12 +237,19 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); + final PersistableBundle networkPrioritiesBundle = + in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); + mUnderlyingNetworkPriorities = + new LinkedHashSet<>( + PersistableBundleUtils.toList( + networkPrioritiesBundle, + VcnUnderlyingNetworkPriority::fromPersistableBundle)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -221,6 +267,7 @@ public final class VcnGatewayConnectionConfig { checkValidCapability(cap); } + Objects.requireNonNull(mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null"); Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); validateRetryInterval(mRetryIntervalsMs); @@ -302,6 +349,18 @@ public final class VcnGatewayConnectionConfig { return Collections.unmodifiableSet(mExposedCapabilities); } + /** + * Retrieve the configured VcnUnderlyingNetworkPriority list, or a default list if it is not + * configured. + * + * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet) + * @hide + */ + @NonNull + public LinkedHashSet getVcnUnderlyingNetworkPriorities() { + return new LinkedHashSet<>(mUnderlyingNetworkPriorities); + } + /** * Retrieves the configured retry intervals. * @@ -338,10 +397,15 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); + final PersistableBundle networkPrioritiesBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mUnderlyingNetworkPriorities), + VcnUnderlyingNetworkPriority::toPersistableBundle); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); + result.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, networkPrioritiesBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -379,6 +443,11 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set mExposedCapabilities = new ArraySet(); + + @NonNull + private final LinkedHashSet mUnderlyingNetworkPriorities = + new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; @@ -449,6 +518,33 @@ public final class VcnGatewayConnectionConfig { return this; } + /** + * Set the VcnUnderlyingNetworkPriority list. + * + * @param underlyingNetworkPriorities a list of unique VcnUnderlyingNetworkPriorities that + * are ordered from most to least preferred, or an empty list to use the default + * prioritization. The default network prioritization is Opportunistic cellular, Carrier + * WiFi and Macro cellular + * @return + */ + /** @hide */ + @NonNull + public Builder setVcnUnderlyingNetworkPriorities( + @NonNull LinkedHashSet underlyingNetworkPriorities) { + Objects.requireNonNull( + mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null"); + + mUnderlyingNetworkPriorities.clear(); + + if (underlyingNetworkPriorities.isEmpty()) { + mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + } else { + mUnderlyingNetworkPriorities.addAll(underlyingNetworkPriorities); + } + + return this; + } + /** * Set the retry interval between VCN establishment attempts upon successive failures. * @@ -513,6 +609,7 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, + mUnderlyingNetworkPriorities, mRetryIntervalsMs, mMaxMtu); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java index 3e47eb1fa4..f7d3697029 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java @@ -31,7 +31,8 @@ public class VcnCellUnderlyingNetworkPriorityTest { private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); - private static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() { + // Package private for use in VcnGatewayConnectionConfigTest + static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() { return new VcnCellUnderlyingNetworkPriority.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index dc338ae0fd..724c33ffb3 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -38,6 +38,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -50,9 +51,17 @@ public class VcnGatewayConnectionConfigTest { }; public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + private static final LinkedHashSet UNDERLYING_NETWORK_PRIORITIES = + new LinkedHashSet(); + static { Arrays.sort(EXPOSED_CAPS); Arrays.sort(UNDERLYING_CAPS); + + UNDERLYING_NETWORK_PRIORITIES.add( + VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + UNDERLYING_NETWORK_PRIORITIES.add( + VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); } public static final long[] RETRY_INTERVALS_MS = @@ -82,7 +91,10 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { - return buildTestConfigWithExposedCaps(EXPOSED_CAPS); + final VcnGatewayConnectionConfig.Builder builder = + newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES); + + return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS); } private static VcnGatewayConnectionConfig.Builder newBuilder() { @@ -158,6 +170,15 @@ public class VcnGatewayConnectionConfigTest { } } + @Test + public void testBuilderRequiresNonNullNetworkPriorities() { + try { + newBuilder().setVcnUnderlyingNetworkPriorities(null); + fail("Expected exception due to invalid underlyingNetworkPriorities"); + } catch (NullPointerException e) { + } + } + @Test public void testBuilderRequiresNonNullRetryInterval() { try { @@ -195,6 +216,7 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); + assertEquals(UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities()); assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java index 69ffeadbff..dd272cb385 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java @@ -30,7 +30,8 @@ public class VcnWifiUnderlyingNetworkPriorityTest { private static final String SSID = "TestWifi"; private static final int INVALID_NETWORK_QUALITY = -1; - private static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() { + // Package private for use in VcnGatewayConnectionConfigTest + static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() { return new VcnWifiUnderlyingNetworkPriority.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) From 65eabdc47af2ffa4140c5e6a50f92fd25f8ef86c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 2 Dec 2021 05:30:19 +0000 Subject: [PATCH 0287/1057] Immediately tear down VCN network when entering Airplane Mode This change immediately tears down the VCN network if all underlying networks are lost, and the device is in airplane mode. This ensures consistency where other components may not understand the lingering behavior of the VCN network Bug: 207014742 Test: atest FrameworksVcnTests Change-Id: Ib05f0c4255e847eed7d8623b35c5a7dfedd920d6 --- .../server/vcn/VcnGatewayConnection.java | 20 ++++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 15 ++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index be13168815..584530c0f3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -77,6 +77,7 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Process; import android.os.SystemClock; +import android.provider.Settings; import android.util.ArraySet; import android.util.Slog; @@ -788,8 +789,19 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/179091925): Move the delayed-message handling to BaseState // If underlying is null, all underlying networks have been lost. Disconnect VCN after a - // timeout. + // timeout (or immediately if in airplane mode, since the device user has indicated that + // the radios should all be turned off). if (underlying == null) { + if (mDeps.isAirplaneModeOn(mVcnContext)) { + sendMessageAndAcquireWakeLock( + EVENT_UNDERLYING_NETWORK_CHANGED, + TOKEN_ALL, + new EventUnderlyingNetworkChangedInfo(null)); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */); + return; + } + setDisconnectRequestAlarm(); } else { // Received a new Network so any previous alarm is irrelevant - cancel + clear it, @@ -2424,6 +2436,12 @@ public class VcnGatewayConnection extends StateMachine { validationStatusCallback); } + /** Checks if airplane mode is enabled. */ + public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) { + return Settings.Global.getInt(vcnContext.getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } + /** Gets the elapsed real time since boot, in millis. */ public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 15de226cdc..e547400fff 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -118,6 +118,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testNullNetworkDoesNotTriggerDisconnect() throws Exception { + doReturn(false).when(mDeps).isAirplaneModeOn(any()); + mGatewayConnection .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(null); @@ -128,6 +130,19 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); } + @Test + public void testNullNetworkAirplaneModeDisconnects() throws Exception { + doReturn(true).when(mDeps).isAirplaneModeOn(any()); + + mGatewayConnection + .getUnderlyingNetworkControllerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).kill(); + } + @Test public void testNewNetworkTriggersMigration() throws Exception { mGatewayConnection From 07e6066cd678887a738e5a5ce31a4d2e2b85da95 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 3 Dec 2021 21:47:36 +0000 Subject: [PATCH 0288/1057] Immediately tear down VCN network when entering Airplane Mode This change immediately tears down the VCN network if all underlying networks are lost, and the device is in airplane mode. This ensures consistency where other components may not understand the lingering behavior of the VCN network Bug: 207014742 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1908637 Merged-In: Ib05f0c4255e847eed7d8623b35c5a7dfedd920d6 Change-Id: Ib05f0c4255e847eed7d8623b35c5a7dfedd920d6 --- .../server/vcn/VcnGatewayConnection.java | 20 ++++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 15 ++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 7dec4e785f..51c3b33b0e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -77,6 +77,7 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Process; import android.os.SystemClock; +import android.provider.Settings; import android.util.ArraySet; import android.util.Slog; @@ -782,8 +783,19 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/179091925): Move the delayed-message handling to BaseState // If underlying is null, all underlying networks have been lost. Disconnect VCN after a - // timeout. + // timeout (or immediately if in airplane mode, since the device user has indicated that + // the radios should all be turned off). if (underlying == null) { + if (mDeps.isAirplaneModeOn(mVcnContext)) { + sendMessageAndAcquireWakeLock( + EVENT_UNDERLYING_NETWORK_CHANGED, + TOKEN_ALL, + new EventUnderlyingNetworkChangedInfo(null)); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */); + return; + } + setDisconnectRequestAlarm(); } else { // Received a new Network so any previous alarm is irrelevant - cancel + clear it, @@ -2414,6 +2426,12 @@ public class VcnGatewayConnection extends StateMachine { validationStatusCallback); } + /** Checks if airplane mode is enabled. */ + public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) { + return Settings.Global.getInt(vcnContext.getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } + /** Gets the elapsed real time since boot, in millis. */ public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index c9a8947ab5..7b5f0b180c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -118,6 +118,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testNullNetworkDoesNotTriggerDisconnect() throws Exception { + doReturn(false).when(mDeps).isAirplaneModeOn(any()); + mGatewayConnection .getUnderlyingNetworkTrackerCallback() .onSelectedUnderlyingNetworkChanged(null); @@ -128,6 +130,19 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */); } + @Test + public void testNullNetworkAirplaneModeDisconnects() throws Exception { + doReturn(true).when(mDeps).isAirplaneModeOn(any()); + + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).kill(); + } + @Test public void testNewNetworkTriggersMigration() throws Exception { mGatewayConnection From 169c07a46ddb08a698514996323e38b0d49aa2b2 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 29 Nov 2021 16:15:06 -0800 Subject: [PATCH 0289/1057] Calculate priority based on caller configurations Update NetworkPriorityClassifier to calculate priority according to the VcnUnderlyingNetworkPriority list configured in VcnGatewayConnectionConfig Bug: 206044122 Test: atest FrameworksVcnTests(new) Test: atest CtsVcnTestCses Change-Id: I55afa916af44db655a568aae2488877f2c177d59 --- .../vcn/VcnCellUnderlyingNetworkPriority.java | 10 + .../net/vcn/VcnGatewayConnectionConfig.java | 4 +- .../net/vcn/VcnUnderlyingNetworkPriority.java | 37 +- .../vcn/VcnWifiUnderlyingNetworkPriority.java | 7 + .../server/vcn/VcnGatewayConnection.java | 4 +- .../NetworkPriorityClassifier.java | 251 ++++++++---- .../UnderlyingNetworkController.java | 36 +- .../UnderlyingNetworkRecord.java | 69 +++- .../vcn/VcnGatewayConnectionTestBase.java | 2 +- .../NetworkPriorityClassifierTest.java | 383 ++++++++++++++++++ .../UnderlyingNetworkControllerTest.java | 66 ++- 11 files changed, 759 insertions(+), 110 deletions(-) create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java index 6b33e4f45c..50a6bfc065 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java @@ -29,6 +29,7 @@ import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; @@ -200,6 +201,15 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork && mRequireOpportunistic == rhs.mRequireOpportunistic; } + /** @hide */ + @Override + void dumpTransportSpecificFields(IndentingPrintWriter pw) { + pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds.toString()); + pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds.toString()); + pw.println("mAllowRoaming: " + mAllowRoaming); + pw.println("mRequireOpportunistic: " + mRequireOpportunistic); + } + /** This class is used to incrementally build WifiNetworkPriority objects. */ public static class Builder extends VcnUnderlyingNetworkPriority.Builder { @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index de4ada2dbc..31e38c0b75 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -160,7 +160,9 @@ public final class VcnGatewayConnectionConfig { TimeUnit.MINUTES.toMillis(15) }; - private static final LinkedHashSet + /** @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final LinkedHashSet DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>(); static { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java index 82f6ae72b4..551f75772b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java @@ -21,8 +21,10 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.PersistableBundle; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -37,10 +39,17 @@ public abstract class VcnUnderlyingNetworkPriority { /** @hide */ protected static final int NETWORK_PRIORITY_TYPE_CELL = 2; - /** Denotes that network quality needs to be OK */ - public static final int NETWORK_QUALITY_OK = 10000; /** Denotes that any network quality is acceptable */ - public static final int NETWORK_QUALITY_ANY = Integer.MAX_VALUE; + public static final int NETWORK_QUALITY_ANY = 0; + /** Denotes that network quality needs to be OK */ + public static final int NETWORK_QUALITY_OK = 100000; + + private static final SparseArray NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>(); + + static { + NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_ANY, "NETWORK_QUALITY_ANY"); + NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_OK, "NETWORK_QUALITY_OK"); + } /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -125,6 +134,28 @@ public abstract class VcnUnderlyingNetworkPriority { && mAllowMetered == rhs.mAllowMetered; } + /** @hide */ + abstract void dumpTransportSpecificFields(IndentingPrintWriter pw); + + /** + * Dumps the state of this record for logging and debugging purposes. + * + * @hide + */ + public void dump(IndentingPrintWriter pw) { + pw.println(this.getClass().getSimpleName() + ":"); + pw.increaseIndent(); + + pw.println( + "mNetworkQuality: " + + NETWORK_QUALITY_TO_STRING_MAP.get( + mNetworkQuality, "Invalid value " + mNetworkQuality)); + pw.println("mAllowMetered: " + mAllowMetered); + dumpTransportSpecificFields(pw); + + pw.decreaseIndent(); + } + /** Retrieve the required network quality. */ @NetworkQuality public int getNetworkQuality() { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java index fc7e7e2c4e..2ba9169277 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import java.util.Objects; @@ -81,6 +82,12 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork return mSsid == rhs.mSsid; } + /** @hide */ + @Override + void dumpTransportSpecificFields(IndentingPrintWriter pw) { + pw.println("mSsid: " + mSsid); + } + /** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */ @Nullable public String getSsid() { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index be13168815..9a216f8c28 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -686,6 +686,7 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkController = mDeps.newUnderlyingNetworkController( mVcnContext, + mConnectionConfig, subscriptionGroup, mLastSnapshot, mUnderlyingNetworkControllerCallback); @@ -2364,11 +2365,12 @@ public class VcnGatewayConnection extends StateMachine { /** Builds a new UnderlyingNetworkController. */ public UnderlyingNetworkController newUnderlyingNetworkController( VcnContext vcnContext, + VcnGatewayConnectionConfig connectionConfig, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkControllerCallback callback) { return new UnderlyingNetworkController( - vcnContext, subscriptionGroup, snapshot, callback); + vcnContext, connectionConfig, subscriptionGroup, snapshot, callback); } /** Builds a new IkeSession. */ diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index bea8ae932a..7b26fe0370 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -15,25 +15,36 @@ */ package com.android.server.vcn.routeselection; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; import static com.android.server.VcnManagementService.LOCAL_LOG; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnCellUnderlyingNetworkPriority; import android.net.vcn.VcnManager; +import android.net.vcn.VcnUnderlyingNetworkPriority; +import android.net.vcn.VcnWifiUnderlyingNetworkPriority; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Slog; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; +import java.util.LinkedHashSet; import java.util.Set; /** @hide */ @@ -56,52 +67,20 @@ class NetworkPriorityClassifier { */ @VisibleForTesting(visibility = Visibility.PRIVATE) static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; - /** Priority for any cellular network for which the subscription is listed as opportunistic */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0; - /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_WIFI_IN_USE = 1; - /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_WIFI_PROSPECTIVE = 2; - /** Priority for any standard macro cellular network */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_MACRO_CELLULAR = 3; + /** Priority for any other networks (including unvalidated, etc) */ @VisibleForTesting(visibility = Visibility.PRIVATE) static final int PRIORITY_ANY = Integer.MAX_VALUE; - private static final SparseArray PRIORITY_TO_STRING_MAP = new SparseArray<>(); - - static { - PRIORITY_TO_STRING_MAP.put( - PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR"); - PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY"); - } - - /** - * Gives networks a priority class, based on the following priorities: - * - *

        - *
      1. Opportunistic cellular - *
      2. Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT - *
      3. Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT - *
      4. Macro cellular - *
      5. Any others - *
      - */ - static int calculatePriorityClass( + /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */ + public static int calculatePriorityClass( + VcnContext vcnContext, UnderlyingNetworkRecord networkRecord, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundle carrierConfig) { - final NetworkCapabilities caps = networkRecord.networkCapabilities; - // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED if (networkRecord.isBlocked) { @@ -109,8 +88,167 @@ class NetworkPriorityClassifier { return PRIORITY_ANY; } - if (caps.hasTransport(TRANSPORT_CELLULAR) - && isOpportunistic(snapshot, caps.getSubscriptionIds())) { + if (snapshot == null) { + logWtf("Got null snapshot"); + return PRIORITY_ANY; + } + + int priorityIndex = 0; + for (VcnUnderlyingNetworkPriority nwPriority : underlyingNetworkPriorities) { + if (checkMatchesPriorityRule( + vcnContext, + nwPriority, + networkRecord, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig)) { + return priorityIndex; + } + priorityIndex++; + } + return PRIORITY_ANY; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static boolean checkMatchesPriorityRule( + VcnContext vcnContext, + VcnUnderlyingNetworkPriority networkPriority, + UnderlyingNetworkRecord networkRecord, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + // TODO: Check Network Quality reported by metric monitors/probers. + + final NetworkCapabilities caps = networkRecord.networkCapabilities; + if (!networkPriority.allowMetered() && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)) { + return false; + } + + if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { + return true; + } + + if (networkPriority instanceof VcnWifiUnderlyingNetworkPriority) { + return checkMatchesWifiPriorityRule( + (VcnWifiUnderlyingNetworkPriority) networkPriority, + networkRecord, + currentlySelected, + carrierConfig); + } + + if (networkPriority instanceof VcnCellUnderlyingNetworkPriority) { + return checkMatchesCellPriorityRule( + vcnContext, + (VcnCellUnderlyingNetworkPriority) networkPriority, + networkRecord, + subscriptionGroup, + snapshot); + } + + logWtf( + "Got unknown VcnUnderlyingNetworkPriority class: " + + networkPriority.getClass().getSimpleName()); + return false; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static boolean checkMatchesWifiPriorityRule( + VcnWifiUnderlyingNetworkPriority networkPriority, + UnderlyingNetworkRecord networkRecord, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkRecord.networkCapabilities; + + if (!caps.hasTransport(TRANSPORT_WIFI)) { + return false; + } + + // TODO: Move the Network Quality check to the network metric monitor framework. + if (networkPriority.getNetworkQuality() + > getWifiQuality(networkRecord, currentlySelected, carrierConfig)) { + return false; + } + + if (networkPriority.getSsid() != null && networkPriority.getSsid() != caps.getSsid()) { + return false; + } + + return true; + } + + private static int getWifiQuality( + UnderlyingNetworkRecord networkRecord, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkRecord.networkCapabilities; + final boolean isSelectedNetwork = + currentlySelected != null + && networkRecord.network.equals(currentlySelected.network); + + if (isSelectedNetwork + && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { + return NETWORK_QUALITY_OK; + } + + if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { + return NETWORK_QUALITY_OK; + } + + return NETWORK_QUALITY_ANY; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static boolean checkMatchesCellPriorityRule( + VcnContext vcnContext, + VcnCellUnderlyingNetworkPriority networkPriority, + UnderlyingNetworkRecord networkRecord, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot) { + final NetworkCapabilities caps = networkRecord.networkCapabilities; + + if (!caps.hasTransport(TRANSPORT_CELLULAR)) { + return false; + } + + final TelephonyNetworkSpecifier telephonyNetworkSpecifier = + ((TelephonyNetworkSpecifier) caps.getNetworkSpecifier()); + if (telephonyNetworkSpecifier == null) { + logWtf("Got null NetworkSpecifier"); + return false; + } + + final int subId = telephonyNetworkSpecifier.getSubscriptionId(); + final TelephonyManager subIdSpecificTelephonyMgr = + vcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .createForSubscriptionId(subId); + + if (!networkPriority.getAllowedPlmnIds().isEmpty()) { + final String plmnId = subIdSpecificTelephonyMgr.getNetworkOperator(); + if (!networkPriority.getAllowedPlmnIds().contains(plmnId)) { + return false; + } + } + + if (!networkPriority.getAllowedSpecificCarrierIds().isEmpty()) { + final int carrierId = subIdSpecificTelephonyMgr.getSimSpecificCarrierId(); + if (!networkPriority.getAllowedSpecificCarrierIds().contains(carrierId)) { + return false; + } + } + + if (!networkPriority.allowRoaming() && !caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)) { + return false; + } + + if (networkPriority.requireOpportunistic()) { + if (!isOpportunistic(snapshot, caps.getSubscriptionIds())) { + return false; + } + // If this carrier is the active data provider, ensure that opportunistic is only // ever prioritized if it is also the active data subscription. This ensures that // if an opportunistic subscription is still in the process of being switched to, @@ -121,36 +259,15 @@ class NetworkPriorityClassifier { // Allow the following two cases: // 1. Active subId is NOT in the group that this VCN is supporting // 2. This opportunistic subscription is for the active subId - if (!snapshot.getAllSubIdsInGroup(subscriptionGroup) + if (snapshot.getAllSubIdsInGroup(subscriptionGroup) .contains(SubscriptionManager.getActiveDataSubscriptionId()) - || caps.getSubscriptionIds() + && !caps.getSubscriptionIds() .contains(SubscriptionManager.getActiveDataSubscriptionId())) { - return PRIORITY_OPPORTUNISTIC_CELLULAR; + return false; } } - if (caps.hasTransport(TRANSPORT_WIFI)) { - if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) - && currentlySelected != null - && networkRecord.network.equals(currentlySelected.network)) { - return PRIORITY_WIFI_IN_USE; - } - - if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { - return PRIORITY_WIFI_PROSPECTIVE; - } - } - - // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might - // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be - // the case if the Default Data SubId does not support certain services (eg voice - // calling) - if (caps.hasTransport(TRANSPORT_CELLULAR) - && !isOpportunistic(snapshot, caps.getSubscriptionIds())) { - return PRIORITY_MACRO_CELLULAR; - } - - return PRIORITY_ANY; + return true; } static boolean isOpportunistic( @@ -185,10 +302,6 @@ class NetworkPriorityClassifier { return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; } - static String priorityClassToString(int priorityClass) { - return PRIORITY_TO_STRING_MAP.get(priorityClass, "unknown"); - } - private static void logWtf(String msg) { Slog.wtf(TAG, msg); LOCAL_LOG.log(TAG + " WTF: " + msg); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 071c7a683c..cd124ee6a9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -32,6 +32,8 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnUnderlyingNetworkPriority; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; @@ -68,6 +70,7 @@ public class UnderlyingNetworkController { @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName(); @NonNull private final VcnContext mVcnContext; + @NonNull private final VcnGatewayConnectionConfig mConnectionConfig; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final UnderlyingNetworkControllerCallback mCb; @NonNull private final Dependencies mDeps; @@ -91,24 +94,22 @@ public class UnderlyingNetworkController { public UnderlyingNetworkController( @NonNull VcnContext vcnContext, + @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull UnderlyingNetworkControllerCallback cb) { - this( - vcnContext, - subscriptionGroup, - snapshot, - cb, - new Dependencies()); + this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies()); } private UnderlyingNetworkController( @NonNull VcnContext vcnContext, + @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, @NonNull UnderlyingNetworkControllerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); mCb = Objects.requireNonNull(cb, "Missing cb"); @@ -399,6 +400,8 @@ public class UnderlyingNetworkController { TreeSet sorted = new TreeSet<>( UnderlyingNetworkRecord.getComparator( + mVcnContext, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, @@ -495,12 +498,31 @@ public class UnderlyingNetworkController { pw.println( "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network)); + pw.println("VcnUnderlyingNetworkPriority list:"); + pw.increaseIndent(); + int index = 0; + for (VcnUnderlyingNetworkPriority priority : + mConnectionConfig.getVcnUnderlyingNetworkPriorities()) { + pw.println("Priority index: " + index); + priority.dump(pw); + index++; + } + pw.decreaseIndent(); + pw.println(); + pw.println("Underlying networks:"); pw.increaseIndent(); if (mRouteSelectionCallback != null) { for (UnderlyingNetworkRecord record : mRouteSelectionCallback.getSortedUnderlyingNetworks()) { - record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig); + record.dump( + mVcnContext, + pw, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCurrentRecord, + mCarrierConfig); } } pw.decreaseIndent(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index 65c69dedcb..27ba854ab1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkPriority; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -28,8 +29,10 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.Objects; /** @@ -73,22 +76,64 @@ public class UnderlyingNetworkRecord { } static Comparator getComparator( + VcnContext vcnContext, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundle carrierConfig) { return (left, right) -> { - return Integer.compare( + final int leftIndex = NetworkPriorityClassifier.calculatePriorityClass( - left, subscriptionGroup, snapshot, currentlySelected, carrierConfig), + vcnContext, + left, + underlyingNetworkPriorities, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); + final int rightIndex = NetworkPriorityClassifier.calculatePriorityClass( - right, subscriptionGroup, snapshot, currentlySelected, carrierConfig)); + vcnContext, + right, + underlyingNetworkPriorities, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); + + // In the case of networks in the same priority class, prioritize based on other + // criteria (eg. actively selected network, link metrics, etc) + if (leftIndex == rightIndex) { + // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord + // fall into the same priority class. + if (isSelected(left, currentlySelected)) { + return -1; + } + if (isSelected(left, currentlySelected)) { + return 1; + } + } + return Integer.compare(leftIndex, rightIndex); }; } + private static boolean isSelected( + UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) { + if (currentlySelected == null) { + return false; + } + if (currentlySelected.network == recordToCheck.network) { + return true; + } + return false; + } + /** Dumps the state of this record for logging and debugging purposes. */ void dump( + VcnContext vcnContext, IndentingPrintWriter pw, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -96,15 +141,17 @@ public class UnderlyingNetworkRecord { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); - final int priorityClass = + final int priorityIndex = NetworkPriorityClassifier.calculatePriorityClass( - this, subscriptionGroup, snapshot, currentlySelected, carrierConfig); - pw.println( - "Priority class: " - + NetworkPriorityClassifier.priorityClassToString(priorityClass) - + " (" - + priorityClass - + ")"); + vcnContext, + this, + underlyingNetworkPriorities, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); + + pw.println("Priority index:" + priorityIndex); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 8a0af2dff8..5628321b59 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -179,7 +179,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkController) .when(mDeps) - .newUnderlyingNetworkController(any(), any(), any(), any()); + .newUnderlyingNetworkController(any(), any(), any(), any(), any()); doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java new file mode 100644 index 0000000000..2e1aab6015 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -0,0 +1,383 @@ +/* + * 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.server.vcn.routeselection; + +import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; + +import static com.android.server.vcn.VcnTestUtils.setupSystemService; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.calculatePriorityClass; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; +import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnCellUnderlyingNetworkPriority; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnManager; +import android.net.vcn.VcnWifiUnderlyingNetworkPriority; +import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.os.test.TestLooper; +import android.telephony.TelephonyManager; +import android.util.ArraySet; + +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Set; +import java.util.UUID; + +public class NetworkPriorityClassifierTest { + private static final String SSID = "TestWifi"; + private static final String SSID_OTHER = "TestWifiOther"; + private static final String PLMN_ID = "123456"; + private static final String PLMN_ID_OTHER = "234567"; + + private static final int SUB_ID = 1; + private static final int WIFI_RSSI = -60; + private static final int WIFI_RSSI_HIGH = -50; + private static final int WIFI_RSSI_LOW = -80; + private static final int CARRIER_ID = 1; + private static final int CARRIER_ID_OTHER = 2; + + private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + + private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSignalStrength(WIFI_RSSI) + .setSsid(SSID) + .build(); + + private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); + private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setSubscriptionIds(Set.of(SUB_ID)) + .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .build(); + + private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); + + @Mock private Network mNetwork; + @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; + @Mock private TelephonyManager mTelephonyManager; + + private TestLooper mTestLooper; + private VcnContext mVcnContext; + private UnderlyingNetworkRecord mWifiNetworkRecord; + private UnderlyingNetworkRecord mCellNetworkRecord; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + final Context mockContext = mock(Context.class); + mTestLooper = new TestLooper(); + mVcnContext = + spy( + new VcnContext( + mockContext, + mTestLooper.getLooper(), + mock(VcnNetworkProvider.class), + false /* isInTestMode */)); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + + mWifiNetworkRecord = + new UnderlyingNetworkRecord( + mNetwork, + WIFI_NETWORK_CAPABILITIES, + LINK_PROPERTIES, + false /* isBlocked */); + + mCellNetworkRecord = + new UnderlyingNetworkRecord( + mNetwork, + CELL_NETWORK_CAPABILITIES, + LINK_PROPERTIES, + false /* isBlocked */); + + setupSystemService( + mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); + when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); + when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); + } + + @Test + public void testMatchWithoutNotMeteredBit() { + final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = + new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(false /* allowMetered */) + .build(); + + assertFalse( + checkMatchesPriorityRule( + mVcnContext, + wifiNetworkPriority, + mWifiNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot, + null /* currentlySelecetd */, + null /* carrierConfig */)); + } + + private void verifyMatchWifi( + boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) { + final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = + new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .build(); + final UnderlyingNetworkRecord selectedNetworkRecord = + isSelectedNetwork ? mWifiNetworkRecord : null; + assertEquals( + expectMatch, + checkMatchesWifiPriorityRule( + wifiNetworkPriority, + mWifiNetworkRecord, + selectedNetworkRecord, + carrierConfig)); + } + + @Test + public void testMatchSelectedWifi() { + verifyMatchWifi( + true /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */); + } + + @Test + public void testMatchSelectedWifiBelowRssiThreshold() { + final PersistableBundle carrierConfig = new PersistableBundle(); + carrierConfig.putInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH); + carrierConfig.putInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH); + + verifyMatchWifi(true /* isSelectedNetwork */, carrierConfig, false /* expectMatch */); + } + + @Test + public void testMatchUnselectedWifi() { + verifyMatchWifi( + false /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */); + } + + @Test + public void testMatchUnselectedWifiBelowRssiThreshold() { + final PersistableBundle carrierConfig = new PersistableBundle(); + carrierConfig.putInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH); + + verifyMatchWifi(false /* isSelectedNetwork */, carrierConfig, false /* expectMatch */); + } + + private void verifyMatchWifiWithSsid(boolean useMatchedSsid, boolean expectMatch) { + final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER; + final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = + new VcnWifiUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setSsid(nwPrioritySsid) + .build(); + + assertEquals( + expectMatch, + checkMatchesWifiPriorityRule( + wifiNetworkPriority, + mWifiNetworkRecord, + null /* currentlySelecetd */, + null /* carrierConfig */)); + } + + @Test + public void testMatchWifiWithSsid() { + verifyMatchWifiWithSsid(true /* useMatchedSsid */, true /* expectMatch */); + } + + @Test + public void testMatchWifiFailWithWrongSsid() { + verifyMatchWifiWithSsid(false /* useMatchedSsid */, false /* expectMatch */); + } + + private static VcnCellUnderlyingNetworkPriority.Builder getCellNetworkPriorityBuilder() { + return new VcnCellUnderlyingNetworkPriority.Builder() + .setNetworkQuality(NETWORK_QUALITY_OK) + .setAllowMetered(true /* allowMetered */) + .setAllowRoaming(true /* allowRoaming */); + } + + @Test + public void testMatchMacroCell() { + assertTrue( + checkMatchesCellPriorityRule( + mVcnContext, + getCellNetworkPriorityBuilder().build(), + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + @Test + public void testMatchOpportunisticCell() { + final VcnCellUnderlyingNetworkPriority opportunisticCellNetworkPriority = + getCellNetworkPriorityBuilder() + .setRequireOpportunistic(true /* requireOpportunistic */) + .build(); + + when(mSubscriptionSnapshot.isOpportunistic(SUB_ID)).thenReturn(true); + when(mSubscriptionSnapshot.getAllSubIdsInGroup(SUB_GROUP)).thenReturn(new ArraySet<>()); + + assertTrue( + checkMatchesCellPriorityRule( + mVcnContext, + opportunisticCellNetworkPriority, + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + private void verifyMatchMacroCellWithAllowedPlmnIds( + boolean useMatchedPlmnId, boolean expectMatch) { + final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER; + final VcnCellUnderlyingNetworkPriority networkPriority = + getCellNetworkPriorityBuilder() + .setAllowedPlmnIds(Set.of(networkPriorityPlmnId)) + .build(); + + assertEquals( + expectMatch, + checkMatchesCellPriorityRule( + mVcnContext, + networkPriority, + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + @Test + public void testMatchMacroCellWithAllowedPlmnIds() { + verifyMatchMacroCellWithAllowedPlmnIds(true /* useMatchedPlmnId */, true /* expectMatch */); + } + + @Test + public void testMatchMacroCellFailWithDisallowedPlmnIds() { + verifyMatchMacroCellWithAllowedPlmnIds( + false /* useMatchedPlmnId */, false /* expectMatch */); + } + + private void verifyMatchMacroCellWithAllowedSpecificCarrierIds( + boolean useMatchedCarrierId, boolean expectMatch) { + final int networkPriorityCarrierId = useMatchedCarrierId ? CARRIER_ID : CARRIER_ID_OTHER; + final VcnCellUnderlyingNetworkPriority networkPriority = + getCellNetworkPriorityBuilder() + .setAllowedSpecificCarrierIds(Set.of(networkPriorityCarrierId)) + .build(); + + assertEquals( + expectMatch, + checkMatchesCellPriorityRule( + mVcnContext, + networkPriority, + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + @Test + public void testMatchMacroCellWithAllowedSpecificCarrierIds() { + verifyMatchMacroCellWithAllowedSpecificCarrierIds( + true /* useMatchedCarrierId */, true /* expectMatch */); + } + + @Test + public void testMatchMacroCellFailWithDisallowedSpecificCarrierIds() { + verifyMatchMacroCellWithAllowedSpecificCarrierIds( + false /* useMatchedCarrierId */, false /* expectMatch */); + } + + @Test + public void testMatchWifiFailWithoutNotRoamingBit() { + final VcnCellUnderlyingNetworkPriority networkPriority = + getCellNetworkPriorityBuilder().setAllowRoaming(false /* allowRoaming */).build(); + + assertFalse( + checkMatchesCellPriorityRule( + mVcnContext, + networkPriority, + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + private void verifyCalculatePriorityClass( + UnderlyingNetworkRecord networkRecord, int expectedIndex) { + final int priorityIndex = + calculatePriorityClass( + mVcnContext, + networkRecord, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES, + SUB_GROUP, + mSubscriptionSnapshot, + null /* currentlySelected */, + null /* carrierConfig */); + + assertEquals(expectedIndex, priorityIndex); + } + + @Test + public void testCalculatePriorityClass() throws Exception { + verifyCalculatePriorityClass(mCellNetworkRecord, 2); + } + + @Test + public void testCalculatePriorityClassFailToMatchAny() throws Exception { + final NetworkCapabilities nc = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSignalStrength(WIFI_RSSI_LOW) + .setSsid(SSID) + .build(); + final UnderlyingNetworkRecord wifiNetworkRecord = + new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */); + + verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index c954cb84df..fad9669911 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -42,6 +42,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; import android.telephony.CarrierConfigManager; @@ -145,7 +146,11 @@ public class UnderlyingNetworkControllerTest { mUnderlyingNetworkController = new UnderlyingNetworkController( - mVcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb); + mVcnContext, + VcnGatewayConnectionConfigTest.buildTestConfig(), + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkControllerCb); } private void resetVcnContext() { @@ -153,7 +158,8 @@ public class UnderlyingNetworkControllerTest { doNothing().when(mVcnContext).ensureRunningOnLooperThread(); } - private static LinkProperties getLinkPropertiesWithName(String iface) { + // Package private for use in NetworkPriorityClassifierTest + static LinkProperties getLinkPropertiesWithName(String iface) { LinkProperties linkProperties = new LinkProperties(); linkProperties.setInterfaceName(iface); return linkProperties; @@ -182,7 +188,11 @@ public class UnderlyingNetworkControllerTest { true /* isInTestMode */); new UnderlyingNetworkController( - vcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb); + vcnContext, + VcnGatewayConnectionConfigTest.buildTestConfig(), + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkControllerCb); verify(cm) .registerNetworkCallback( @@ -345,6 +355,17 @@ public class UnderlyingNetworkControllerTest { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } + private static NetworkCapabilities buildResponseNwCaps( + NetworkCapabilities requestNetworkCaps, Set netCapsSubIds) { + final TelephonyNetworkSpecifier telephonyNetworkSpecifier = + new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(netCapsSubIds.iterator().next()) + .build(); + return new NetworkCapabilities.Builder(requestNetworkCaps) + .setNetworkSpecifier(telephonyNetworkSpecifier) + .build(); + } + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) @@ -355,14 +376,17 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue(); cb.onAvailable(mNetwork); - cb.onCapabilitiesChanged(mNetwork, networkCapabilities); + + final NetworkCapabilities responseNetworkCaps = + buildResponseNwCaps(networkCapabilities, INITIAL_SUB_IDS); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); cb.onBlockedStatusChanged(mNetwork, false /* isFalse */); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - networkCapabilities, + responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); @@ -373,12 +397,14 @@ public class UnderlyingNetworkControllerTest { public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); - cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); + final NetworkCapabilities responseNetworkCaps = + buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - UPDATED_NETWORK_CAPABILITIES, + responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); @@ -393,7 +419,7 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - INITIAL_NETWORK_CAPABILITIES, + buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), UPDATED_LINK_PROPERTIES, false /* isBlocked */); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); @@ -403,19 +429,21 @@ public class UnderlyingNetworkControllerTest { public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); - cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); + final NetworkCapabilities responseNetworkCaps = + buildResponseNwCaps(SUSPENDED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - SUSPENDED_NETWORK_CAPABILITIES, + responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); verify(mNetworkControllerCb, times(1)) .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. - cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); verify(mNetworkControllerCb, times(1)) .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @@ -425,19 +453,21 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); - cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + final NetworkCapabilities responseNetworkCaps = + buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - INITIAL_NETWORK_CAPABILITIES, + responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); verify(mNetworkControllerCb, times(1)) .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. - cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); verify(mNetworkControllerCb, times(1)) .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); } @@ -451,7 +481,7 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkRecord expectedRecord = new UnderlyingNetworkRecord( mNetwork, - INITIAL_NETWORK_CAPABILITIES, + buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), INITIAL_LINK_PROPERTIES, true /* isBlocked */); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); @@ -470,7 +500,8 @@ public class UnderlyingNetworkControllerTest { public void testRecordTrackerCallbackIgnoresDuplicateRecord() { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); - cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); + cb.onCapabilitiesChanged( + mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS)); // Verify no more calls to the UnderlyingNetworkControllerCallback when the // UnderlyingNetworkRecord does not actually change @@ -482,7 +513,8 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); mUnderlyingNetworkController.teardown(); - cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); + cb.onCapabilitiesChanged( + mNetwork, buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, INITIAL_SUB_IDS)); // Verify that the only call was during onAvailable() verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); From 99e9878d76dc786360cbcb9def8e0bb755db0375 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Dec 2021 18:04:40 -0800 Subject: [PATCH 0290/1057] Update #hashCode & #equals with mUnderlyingNetworkPriorities Update VcnGatewayConnectionConfig to consider mUnderlyingNetworkPriorities in #hashCode and #equals methods Rename #setAllowedPlmnIds and #getAllowedPlmnIds to #setAllowedOperatorPlmnIds and #getAllowedOperatorPlmnIds Bug: 206044122 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: Id16d88024bbb7ef275da0304f2dde1413a18de10 --- .../vcn/VcnCellUnderlyingNetworkPriority.java | 6 ++-- .../net/vcn/VcnGatewayConnectionConfig.java | 2 ++ .../vcn/VcnWifiUnderlyingNetworkPriority.java | 2 +- .../NetworkPriorityClassifier.java | 4 +-- .../VcnCellUnderlyingNetworkPriorityTest.java | 6 ++-- .../vcn/VcnGatewayConnectionConfigTest.java | 36 +++++++++++++++++++ .../NetworkPriorityClassifierTest.java | 2 +- 7 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java index 50a6bfc065..b3f7345240 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java @@ -151,7 +151,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork /** Retrieve the allowed PLMN IDs, or an empty set if any PLMN ID is acceptable. */ @NonNull - public Set getAllowedPlmnIds() { + public Set getAllowedOperatorPlmnIds() { return Collections.unmodifiableSet(mAllowedNetworkPlmnIds); } @@ -211,7 +211,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork } /** This class is used to incrementally build WifiNetworkPriority objects. */ - public static class Builder extends VcnUnderlyingNetworkPriority.Builder { + public static final class Builder extends VcnUnderlyingNetworkPriority.Builder { @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); @NonNull private final Set mAllowedSpecificCarrierIds = new ArraySet<>(); @@ -233,7 +233,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork * and {@link SubscriptionInfo#getMncString()}. */ @NonNull - public Builder setAllowedPlmnIds(@NonNull Set allowedNetworkPlmnIds) { + public Builder setAllowedOperatorPlmnIds(@NonNull Set allowedNetworkPlmnIds) { validatePlmnIds(allowedNetworkPlmnIds); mAllowedNetworkPlmnIds.clear(); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 31e38c0b75..0bd146cbc1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -420,6 +420,7 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, + mUnderlyingNetworkPriorities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); } @@ -434,6 +435,7 @@ public final class VcnGatewayConnectionConfig { return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) && mExposedCapabilities.equals(rhs.mExposedCapabilities) + && mUnderlyingNetworkPriorities.equals(rhs.mUnderlyingNetworkPriorities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java index 2ba9169277..85eb100779 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java @@ -79,7 +79,7 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork } final VcnWifiUnderlyingNetworkPriority rhs = (VcnWifiUnderlyingNetworkPriority) other; - return mSsid == rhs.mSsid; + return mSsid.equals(rhs.mSsid); } /** @hide */ diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 7b26fe0370..4576957511 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -226,9 +226,9 @@ class NetworkPriorityClassifier { .getSystemService(TelephonyManager.class) .createForSubscriptionId(subId); - if (!networkPriority.getAllowedPlmnIds().isEmpty()) { + if (!networkPriority.getAllowedOperatorPlmnIds().isEmpty()) { final String plmnId = subIdSpecificTelephonyMgr.getNetworkOperator(); - if (!networkPriority.getAllowedPlmnIds().contains(plmnId)) { + if (!networkPriority.getAllowedOperatorPlmnIds().contains(plmnId)) { return false; } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java index f7d3697029..476be44ee7 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java @@ -36,7 +36,7 @@ public class VcnCellUnderlyingNetworkPriorityTest { return new VcnCellUnderlyingNetworkPriority.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) - .setAllowedPlmnIds(ALLOWED_PLMN_IDS) + .setAllowedOperatorPlmnIds(ALLOWED_PLMN_IDS) .setAllowedSpecificCarrierIds(ALLOWED_CARRIER_IDS) .setAllowRoaming(true /* allowRoaming */) .setRequireOpportunistic(true /* requireOpportunistic */) @@ -48,7 +48,7 @@ public class VcnCellUnderlyingNetworkPriorityTest { final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); assertTrue(networkPriority.allowMetered()); - assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedPlmnIds()); + assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedOperatorPlmnIds()); assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getAllowedSpecificCarrierIds()); assertTrue(networkPriority.allowRoaming()); assertTrue(networkPriority.requireOpportunistic()); @@ -60,7 +60,7 @@ public class VcnCellUnderlyingNetworkPriorityTest { new VcnCellUnderlyingNetworkPriority.Builder().build(); assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); assertFalse(networkPriority.allowMetered()); - assertEquals(new HashSet(), networkPriority.getAllowedPlmnIds()); + assertEquals(new HashSet(), networkPriority.getAllowedOperatorPlmnIds()); assertEquals(new HashSet(), networkPriority.getAllowedSpecificCarrierIds()); assertFalse(networkPriority.allowRoaming()); assertFalse(networkPriority.requireOpportunistic()); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 724c33ffb3..18518aac77 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -271,4 +271,40 @@ public class VcnGatewayConnectionConfigTest { assertNotEquals(tunnelParams, anotherTunnelParams); assertNotEquals(config, anotherConfig); } + + private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkPriorities( + LinkedHashSet networkPriorities) { + return buildTestConfigWithExposedCaps( + new VcnGatewayConnectionConfig.Builder( + "buildTestConfigWithVcnUnderlyingNetworkPriorities", + TUNNEL_CONNECTION_PARAMS) + .setVcnUnderlyingNetworkPriorities(networkPriorities), + EXPOSED_CAPS); + } + + @Test + public void testVcnUnderlyingNetworkPrioritiesEquality() throws Exception { + final VcnGatewayConnectionConfig config = + buildTestConfigWithVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES); + + final LinkedHashSet networkPrioritiesEqual = + new LinkedHashSet(); + networkPrioritiesEqual.add(VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + networkPrioritiesEqual.add(VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + final VcnGatewayConnectionConfig configEqual = + buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesEqual); + + final LinkedHashSet networkPrioritiesNotEqual = + new LinkedHashSet(); + networkPrioritiesNotEqual.add( + VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + final VcnGatewayConnectionConfig configNotEqual = + buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesNotEqual); + + assertEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesEqual); + assertEquals(config, configEqual); + + assertNotEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesNotEqual); + assertNotEquals(config, configNotEqual); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 2e1aab6015..46a614f60a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -279,7 +279,7 @@ public class NetworkPriorityClassifierTest { final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER; final VcnCellUnderlyingNetworkPriority networkPriority = getCellNetworkPriorityBuilder() - .setAllowedPlmnIds(Set.of(networkPriorityPlmnId)) + .setAllowedOperatorPlmnIds(Set.of(networkPriorityPlmnId)) .build(); assertEquals( From 42699d14641d3c37b424e11b37d7888f8316ca3d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 8 Dec 2021 10:53:20 -0800 Subject: [PATCH 0291/1057] Support parsing VcnGatewayConnectionConfig without UnderlyingNetworkPriorities This commit fixes the NullPointerException issue in converting a PersistableBundle without UnderlyingNetworkPriorities to a VcnGatewayConnectionConfig, by adding a null check and building the VcnGatewayConnectionConfig with the default UnderlyingNetworkPriority list. Bug: 209142575 Test: atest FrameworksVcnTests (new tests), CtsVcnTestCases Change-Id: I888d2994c86ba250c3fc9ee1851dccb5e6ef3e77 --- .../net/vcn/VcnGatewayConnectionConfig.java | 34 ++++++++++++++----- .../vcn/VcnGatewayConnectionConfigTest.java | 13 +++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 0bd146cbc1..55d3ecd2c9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -198,7 +198,10 @@ public final class VcnGatewayConnectionConfig { private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet mExposedCapabilities; - private static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities"; + /** @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities"; + @NonNull private final LinkedHashSet mUnderlyingNetworkPriorities; private static final String MAX_MTU_KEY = "mMaxMtu"; @@ -229,6 +232,8 @@ public final class VcnGatewayConnectionConfig { validate(); } + // Null check MUST be done for all new fields added to VcnGatewayConnectionConfig, to avoid + // crashes when parsing PersistableBundle built on old platforms. /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { @@ -239,19 +244,30 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); - final PersistableBundle networkPrioritiesBundle = - in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY); - mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingNetworkPriorities = - new LinkedHashSet<>( - PersistableBundleUtils.toList( - networkPrioritiesBundle, - VcnUnderlyingNetworkPriority::fromPersistableBundle)); + + final PersistableBundle networkPrioritiesBundle = + in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY); + + if (networkPrioritiesBundle == null) { + // UNDERLYING_NETWORK_PRIORITIES_KEY was added in Android T. Thus + // VcnGatewayConnectionConfig created on old platforms will not have this data and will + // be assigned with the default value + mUnderlyingNetworkPriorities = + new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + + } else { + mUnderlyingNetworkPriorities = + new LinkedHashSet<>( + PersistableBundleUtils.toList( + networkPrioritiesBundle, + VcnUnderlyingNetworkPriority::fromPersistableBundle)); + } + mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 18518aac77..377f526a98 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -17,6 +17,8 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES; +import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_PRIORITIES_KEY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -30,6 +32,7 @@ import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; +import android.os.PersistableBundle; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -230,6 +233,16 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } + @Test + public void testParsePersistableBundleWithoutVcnUnderlyingNetworkPriorities() { + PersistableBundle configBundle = buildTestConfig().toPersistableBundle(); + configBundle.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, null); + + final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle); + assertEquals( + DEFAULT_UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities()); + } + private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) { final IkeSessionParams ikeParams = IkeSessionParamsUtilsTest.createBuilderMinimum() From 8c5e8ca44ffbcec49d119b923fb552a1092617de Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Tue, 7 Dec 2021 20:01:45 +0000 Subject: [PATCH 0292/1057] Migrate unsafe parcel APIs in framework-minus-apex Migrate the following unsafe parcel APIs in framework-minus-apex: * Parcel.readSerializable() * Parcel.readArrayList() * Parcel.readList() * Parcel.readParcelable() * Parcel.readParcelableList() * Parcel.readSparseArray() This CL was generated by applying lint fixes that infer the expected type from the caller code and provide that as the type parameter (ag/16365240). A few observations: * In some classes we couldn't migrate because the class also belonged to another build module whose min SDK wasn't current (as is the case for framework-minus-apex), hence I suppressed the lint check (since I'll eventually submit the lint check to the tree). * In some cases, I needed to do the cast in https://stackoverflow.com/a/1080525/5765705 to make the compiler happy since there isn't another way of providing a class of type Class>. * In the readSerializable() case, the new API also requires the class loader, that was inferred to by InferredClass.class.getClassLoader(). * Note that automatic formatting and import rely on running hooked up to the IDE, which wasn't the case here. Bug: 195622897 Test: TH passes Change-Id: I11a27b9bdab7959ee86e90aa1e1cbebd7aaf883c --- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java | 2 +- .../src/android/net/vcn/VcnUnderlyingNetworkPolicy.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index caab15251f..fd3fe3731b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -173,7 +173,7 @@ public final class VcnConfig implements Parcelable { new Parcelable.Creator() { @NonNull public VcnConfig createFromParcel(Parcel in) { - return new VcnConfig((PersistableBundle) in.readParcelable(null)); + return new VcnConfig((PersistableBundle) in.readParcelable(null, android.os.PersistableBundle.class)); } @NonNull diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index 14e70cfeb1..fca084a00a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -114,7 +114,7 @@ public final class VcnNetworkPolicyResult implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnNetworkPolicyResult createFromParcel(Parcel in) { - return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null, android.net.NetworkCapabilities.class)); } public VcnNetworkPolicyResult[] newArray(int size) { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 25a257423c..5c47b28a7c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -146,7 +146,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); - final WifiInfo wifiInfo = in.readParcelable(null); + final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class); // If all fields are their null values, return null TransportInfo to avoid // leaking information about this being a VCN Network (instead of macro diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index b0d4f3be24..2b5305d05d 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -106,7 +106,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null, android.net.vcn.VcnNetworkPolicyResult.class)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { From ed5ae8b6083f8ce0ce5f2d2f06392c3363b37de1 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Dec 2021 13:29:46 -0800 Subject: [PATCH 0293/1057] Added a new network capability MMTEL Added NET_CAPABILITY_MMTEL to indicate a network support MMTEL (Multimedia telephony). This is for IMS service to request an IMS network that supports voice or PS (VoPS for 4G, VoNR for 5G). Bug: 210774375 Test: atest ConnectivityServiceTest Change-Id: I2c7b291fee3450f588a282f7a252c183c374becf (cherry picked from commit 1e6438b43a13c27d0f939ec417dc0a84597fe935) --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 55d3ecd2c9..39b5e7b3da 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -74,6 +74,7 @@ import java.util.concurrent.TimeUnit; *
    • {@link NetworkCapabilities#NET_CAPABILITY_CBS} *
    • {@link NetworkCapabilities#NET_CAPABILITY_IA} *
    • {@link NetworkCapabilities#NET_CAPABILITY_RCS} + *
    • {@link NetworkCapabilities#NET_CAPABILITY_MMTEL} *
    • {@link NetworkCapabilities#NET_CAPABILITY_XCAP} *
    • {@link NetworkCapabilities#NET_CAPABILITY_EIMS} *
    • {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} @@ -102,6 +103,7 @@ public final class VcnGatewayConnectionConfig { allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMTEL); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); From 9e682685131b3e0029a2d83c52ad69ae1907cc61 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 21 Dec 2021 11:24:01 +0000 Subject: [PATCH 0294/1057] Revert "Added a new network capability MMTEL" Revert "Added a new network capability MMTEL" Revert submission 1927643-mmtel_capability Reason for revert: b/211586152 Reverted Changes: Ifea8b1e40:Added a new network capability MMTEL I38655bef2:Added a new network capability MMTEL I837606d9e:Added setup/tear down data support I2c7b291fe:Added a new network capability MMTEL Change-Id: Ifd818ba06bc8c6a10bf0393243443d049e5d7503 --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 39b5e7b3da..55d3ecd2c9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -74,7 +74,6 @@ import java.util.concurrent.TimeUnit; *
    • {@link NetworkCapabilities#NET_CAPABILITY_CBS} *
    • {@link NetworkCapabilities#NET_CAPABILITY_IA} *
    • {@link NetworkCapabilities#NET_CAPABILITY_RCS} - *
    • {@link NetworkCapabilities#NET_CAPABILITY_MMTEL} *
    • {@link NetworkCapabilities#NET_CAPABILITY_XCAP} *
    • {@link NetworkCapabilities#NET_CAPABILITY_EIMS} *
    • {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} @@ -103,7 +102,6 @@ public final class VcnGatewayConnectionConfig { allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); - allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMTEL); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); From 7a0a8747e3f6644b7b6c2e292b929098ad398a9b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 14 Dec 2021 16:24:15 -0800 Subject: [PATCH 0295/1057] Rename VcnUnderlyingNetworkPrioirty to VcnUnderlyingNetworkTemplate Rename the classes' names as well as the test files. Bug: 206044122 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: I19d13acf0e46921a7254a39dff2af332c36ab2b2 --- ... => VcnCellUnderlyingNetworkTemplate.java} | 20 ++++++------- .../net/vcn/VcnGatewayConnectionConfig.java | 30 +++++++++---------- ...java => VcnUnderlyingNetworkTemplate.java} | 16 +++++----- ... => VcnWifiUnderlyingNetworkTemplate.java} | 22 +++++++------- .../NetworkPriorityClassifier.java | 30 +++++++++---------- .../UnderlyingNetworkController.java | 6 ++-- .../UnderlyingNetworkRecord.java | 6 ++-- ...VcnCellUnderlyingNetworkTemplateTest.java} | 20 ++++++------- .../vcn/VcnGatewayConnectionConfigTest.java | 18 +++++------ ...VcnWifiUnderlyingNetworkTemplateTest.java} | 22 +++++++------- .../NetworkPriorityClassifierTest.java | 30 +++++++++---------- 11 files changed, 110 insertions(+), 110 deletions(-) rename Vcn/framework-b/src/android/net/vcn/{VcnCellUnderlyingNetworkPriority.java => VcnCellUnderlyingNetworkTemplate.java} (94%) rename Vcn/framework-b/src/android/net/vcn/{VcnUnderlyingNetworkPriority.java => VcnUnderlyingNetworkTemplate.java} (93%) rename Vcn/framework-b/src/android/net/vcn/{VcnWifiUnderlyingNetworkPriority.java => VcnWifiUnderlyingNetworkTemplate.java} (81%) rename Vcn/tests/unit/java/android/net/vcn/{VcnCellUnderlyingNetworkPriorityTest.java => VcnCellUnderlyingNetworkTemplateTest.java} (81%) rename Vcn/tests/unit/java/android/net/vcn/{VcnWifiUnderlyingNetworkPriorityTest.java => VcnWifiUnderlyingNetworkTemplateTest.java} (77%) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java similarity index 94% rename from Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java rename to Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index b3f7345240..1ac3f0a6d7 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -39,7 +39,7 @@ import java.util.Set; // TODO: Add documents /** @hide */ -public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority { +public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds"; @NonNull private final Set mAllowedNetworkPlmnIds; private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds"; @@ -51,7 +51,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork private static final String REQUIRE_OPPORTUNISTIC_KEY = "mRequireOpportunistic"; private final boolean mRequireOpportunistic; - private VcnCellUnderlyingNetworkPriority( + private VcnCellUnderlyingNetworkTemplate( int networkQuality, boolean allowMetered, Set allowedNetworkPlmnIds, @@ -92,7 +92,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork /** @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) - public static VcnCellUnderlyingNetworkPriority fromPersistableBundle( + public static VcnCellUnderlyingNetworkTemplate fromPersistableBundle( @NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle is null"); @@ -117,7 +117,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork final boolean allowRoaming = in.getBoolean(ALLOW_ROAMING_KEY); final boolean requireOpportunistic = in.getBoolean(REQUIRE_OPPORTUNISTIC_KEY); - return new VcnCellUnderlyingNetworkPriority( + return new VcnCellUnderlyingNetworkTemplate( networkQuality, allowMetered, allowedNetworkPlmnIds, @@ -190,11 +190,11 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork return false; } - if (!(other instanceof VcnCellUnderlyingNetworkPriority)) { + if (!(other instanceof VcnCellUnderlyingNetworkTemplate)) { return false; } - final VcnCellUnderlyingNetworkPriority rhs = (VcnCellUnderlyingNetworkPriority) other; + final VcnCellUnderlyingNetworkTemplate rhs = (VcnCellUnderlyingNetworkTemplate) other; return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds) && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds) && mAllowRoaming == rhs.mAllowRoaming @@ -211,7 +211,7 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork } /** This class is used to incrementally build WifiNetworkPriority objects. */ - public static final class Builder extends VcnUnderlyingNetworkPriority.Builder { + public static final class Builder extends VcnUnderlyingNetworkTemplate.Builder { @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); @NonNull private final Set mAllowedSpecificCarrierIds = new ArraySet<>(); @@ -280,10 +280,10 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork return this; } - /** Build the VcnCellUnderlyingNetworkPriority. */ + /** Build the VcnCellUnderlyingNetworkTemplate. */ @NonNull - public VcnCellUnderlyingNetworkPriority build() { - return new VcnCellUnderlyingNetworkPriority( + public VcnCellUnderlyingNetworkTemplate build() { + return new VcnCellUnderlyingNetworkTemplate( mNetworkQuality, mAllowMetered, mAllowedNetworkPlmnIds, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 55d3ecd2c9..d07c24a652 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,7 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.internal.annotations.VisibleForTesting.Visibility; @@ -162,12 +162,12 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) - public static final LinkedHashSet + public static final LinkedHashSet DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>(); static { DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( - new VcnCellUnderlyingNetworkPriority.Builder() + new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setAllowRoaming(true /* allowRoaming */) @@ -175,13 +175,13 @@ public final class VcnGatewayConnectionConfig { .build()); DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( - new VcnWifiUnderlyingNetworkPriority.Builder() + new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .build()); DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( - new VcnCellUnderlyingNetworkPriority.Builder() + new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setAllowRoaming(true /* allowRoaming */) @@ -202,7 +202,7 @@ public final class VcnGatewayConnectionConfig { @VisibleForTesting(visibility = Visibility.PRIVATE) public static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities"; - @NonNull private final LinkedHashSet mUnderlyingNetworkPriorities; + @NonNull private final LinkedHashSet mUnderlyingNetworkPriorities; private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -215,7 +215,7 @@ public final class VcnGatewayConnectionConfig { @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, - @NonNull LinkedHashSet underlyingNetworkPriorities, + @NonNull LinkedHashSet underlyingNetworkPriorities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; @@ -265,7 +265,7 @@ public final class VcnGatewayConnectionConfig { new LinkedHashSet<>( PersistableBundleUtils.toList( networkPrioritiesBundle, - VcnUnderlyingNetworkPriority::fromPersistableBundle)); + VcnUnderlyingNetworkTemplate::fromPersistableBundle)); } mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); @@ -368,14 +368,14 @@ public final class VcnGatewayConnectionConfig { } /** - * Retrieve the configured VcnUnderlyingNetworkPriority list, or a default list if it is not + * Retrieve the configured VcnUnderlyingNetworkTemplate list, or a default list if it is not * configured. * - * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet) + * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet) * @hide */ @NonNull - public LinkedHashSet getVcnUnderlyingNetworkPriorities() { + public LinkedHashSet getVcnUnderlyingNetworkPriorities() { return new LinkedHashSet<>(mUnderlyingNetworkPriorities); } @@ -418,7 +418,7 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle networkPrioritiesBundle = PersistableBundleUtils.fromList( new ArrayList<>(mUnderlyingNetworkPriorities), - VcnUnderlyingNetworkPriority::toPersistableBundle); + VcnUnderlyingNetworkTemplate::toPersistableBundle); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); @@ -465,7 +465,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull - private final LinkedHashSet mUnderlyingNetworkPriorities = + private final LinkedHashSet mUnderlyingNetworkPriorities = new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -539,7 +539,7 @@ public final class VcnGatewayConnectionConfig { } /** - * Set the VcnUnderlyingNetworkPriority list. + * Set the VcnUnderlyingNetworkTemplate list. * * @param underlyingNetworkPriorities a list of unique VcnUnderlyingNetworkPriorities that * are ordered from most to least preferred, or an empty list to use the default @@ -550,7 +550,7 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @NonNull public Builder setVcnUnderlyingNetworkPriorities( - @NonNull LinkedHashSet underlyingNetworkPriorities) { + @NonNull LinkedHashSet underlyingNetworkPriorities) { Objects.requireNonNull( mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null"); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java similarity index 93% rename from Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java rename to Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 551f75772b..d306d5cb68 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -33,7 +33,7 @@ import java.util.Objects; // TODO: Add documents /** @hide */ -public abstract class VcnUnderlyingNetworkPriority { +public abstract class VcnUnderlyingNetworkTemplate { /** @hide */ protected static final int NETWORK_PRIORITY_TYPE_WIFI = 1; /** @hide */ @@ -68,7 +68,7 @@ public abstract class VcnUnderlyingNetworkPriority { private final boolean mAllowMetered; /** @hide */ - protected VcnUnderlyingNetworkPriority( + protected VcnUnderlyingNetworkTemplate( int networkPriorityType, int networkQuality, boolean allowMetered) { mNetworkPriorityType = networkPriorityType; mNetworkQuality = networkQuality; @@ -89,16 +89,16 @@ public abstract class VcnUnderlyingNetworkPriority { /** @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) - public static VcnUnderlyingNetworkPriority fromPersistableBundle( + public static VcnUnderlyingNetworkTemplate fromPersistableBundle( @NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle is null"); final int networkPriorityType = in.getInt(NETWORK_PRIORITY_TYPE_KEY); switch (networkPriorityType) { case NETWORK_PRIORITY_TYPE_WIFI: - return VcnWifiUnderlyingNetworkPriority.fromPersistableBundle(in); + return VcnWifiUnderlyingNetworkTemplate.fromPersistableBundle(in); case NETWORK_PRIORITY_TYPE_CELL: - return VcnCellUnderlyingNetworkPriority.fromPersistableBundle(in); + return VcnCellUnderlyingNetworkTemplate.fromPersistableBundle(in); default: throw new IllegalArgumentException( "Invalid networkPriorityType:" + networkPriorityType); @@ -124,11 +124,11 @@ public abstract class VcnUnderlyingNetworkPriority { @Override public boolean equals(@Nullable Object other) { - if (!(other instanceof VcnUnderlyingNetworkPriority)) { + if (!(other instanceof VcnUnderlyingNetworkTemplate)) { return false; } - final VcnUnderlyingNetworkPriority rhs = (VcnUnderlyingNetworkPriority) other; + final VcnUnderlyingNetworkTemplate rhs = (VcnUnderlyingNetworkTemplate) other; return mNetworkPriorityType == rhs.mNetworkPriorityType && mNetworkQuality == rhs.mNetworkQuality && mAllowMetered == rhs.mAllowMetered; @@ -168,7 +168,7 @@ public abstract class VcnUnderlyingNetworkPriority { } /** - * This class is used to incrementally build VcnUnderlyingNetworkPriority objects. + * This class is used to incrementally build VcnUnderlyingNetworkTemplate objects. * * @param The subclass to be built. */ diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java similarity index 81% rename from Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java rename to Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 85eb100779..6bbb2bfecd 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -28,11 +28,11 @@ import java.util.Objects; // TODO: Add documents /** @hide */ -public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority { +public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { private static final String SSID_KEY = "mSsid"; @Nullable private final String mSsid; - private VcnWifiUnderlyingNetworkPriority( + private VcnWifiUnderlyingNetworkTemplate( int networkQuality, boolean allowMetered, String ssid) { super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, allowMetered); mSsid = ssid; @@ -43,14 +43,14 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork /** @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) - public static VcnWifiUnderlyingNetworkPriority fromPersistableBundle( + public static VcnWifiUnderlyingNetworkTemplate fromPersistableBundle( @NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle is null"); final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY); final String ssid = in.getString(SSID_KEY); - return new VcnWifiUnderlyingNetworkPriority(networkQuality, allowMetered, ssid); + return new VcnWifiUnderlyingNetworkTemplate(networkQuality, allowMetered, ssid); } /** @hide */ @@ -74,11 +74,11 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork return false; } - if (!(other instanceof VcnWifiUnderlyingNetworkPriority)) { + if (!(other instanceof VcnWifiUnderlyingNetworkTemplate)) { return false; } - final VcnWifiUnderlyingNetworkPriority rhs = (VcnWifiUnderlyingNetworkPriority) other; + final VcnWifiUnderlyingNetworkTemplate rhs = (VcnWifiUnderlyingNetworkTemplate) other; return mSsid.equals(rhs.mSsid); } @@ -94,8 +94,8 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork return mSsid; } - /** This class is used to incrementally build VcnWifiUnderlyingNetworkPriority objects. */ - public static class Builder extends VcnUnderlyingNetworkPriority.Builder { + /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ + public static class Builder extends VcnUnderlyingNetworkTemplate.Builder { @Nullable private String mSsid; /** Construct a Builder object. */ @@ -112,10 +112,10 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork return this; } - /** Build the VcnWifiUnderlyingNetworkPriority. */ + /** Build the VcnWifiUnderlyingNetworkTemplate. */ @NonNull - public VcnWifiUnderlyingNetworkPriority build() { - return new VcnWifiUnderlyingNetworkPriority(mNetworkQuality, mAllowMetered, mSsid); + public VcnWifiUnderlyingNetworkTemplate build() { + return new VcnWifiUnderlyingNetworkTemplate(mNetworkQuality, mAllowMetered, mSsid); } /** @hide */ diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 4576957511..bd8d13b871 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -20,8 +20,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.server.VcnManagementService.LOCAL_LOG; @@ -29,10 +29,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; -import android.net.vcn.VcnCellUnderlyingNetworkPriority; +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnManager; -import android.net.vcn.VcnUnderlyingNetworkPriority; -import android.net.vcn.VcnWifiUnderlyingNetworkPriority; +import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.SubscriptionManager; @@ -76,7 +76,7 @@ class NetworkPriorityClassifier { public static int calculatePriorityClass( VcnContext vcnContext, UnderlyingNetworkRecord networkRecord, - LinkedHashSet underlyingNetworkPriorities, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -94,7 +94,7 @@ class NetworkPriorityClassifier { } int priorityIndex = 0; - for (VcnUnderlyingNetworkPriority nwPriority : underlyingNetworkPriorities) { + for (VcnUnderlyingNetworkTemplate nwPriority : underlyingNetworkPriorities) { if (checkMatchesPriorityRule( vcnContext, nwPriority, @@ -113,7 +113,7 @@ class NetworkPriorityClassifier { @VisibleForTesting(visibility = Visibility.PRIVATE) public static boolean checkMatchesPriorityRule( VcnContext vcnContext, - VcnUnderlyingNetworkPriority networkPriority, + VcnUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, @@ -130,32 +130,32 @@ class NetworkPriorityClassifier { return true; } - if (networkPriority instanceof VcnWifiUnderlyingNetworkPriority) { + if (networkPriority instanceof VcnWifiUnderlyingNetworkTemplate) { return checkMatchesWifiPriorityRule( - (VcnWifiUnderlyingNetworkPriority) networkPriority, + (VcnWifiUnderlyingNetworkTemplate) networkPriority, networkRecord, currentlySelected, carrierConfig); } - if (networkPriority instanceof VcnCellUnderlyingNetworkPriority) { + if (networkPriority instanceof VcnCellUnderlyingNetworkTemplate) { return checkMatchesCellPriorityRule( vcnContext, - (VcnCellUnderlyingNetworkPriority) networkPriority, + (VcnCellUnderlyingNetworkTemplate) networkPriority, networkRecord, subscriptionGroup, snapshot); } logWtf( - "Got unknown VcnUnderlyingNetworkPriority class: " + "Got unknown VcnUnderlyingNetworkTemplate class: " + networkPriority.getClass().getSimpleName()); return false; } @VisibleForTesting(visibility = Visibility.PRIVATE) public static boolean checkMatchesWifiPriorityRule( - VcnWifiUnderlyingNetworkPriority networkPriority, + VcnWifiUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, UnderlyingNetworkRecord currentlySelected, PersistableBundle carrierConfig) { @@ -202,7 +202,7 @@ class NetworkPriorityClassifier { @VisibleForTesting(visibility = Visibility.PRIVATE) public static boolean checkMatchesCellPriorityRule( VcnContext vcnContext, - VcnCellUnderlyingNetworkPriority networkPriority, + VcnCellUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot) { diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index cd124ee6a9..ca2e449ffc 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -33,7 +33,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnGatewayConnectionConfig; -import android.net.vcn.VcnUnderlyingNetworkPriority; +import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; @@ -498,10 +498,10 @@ public class UnderlyingNetworkController { pw.println( "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network)); - pw.println("VcnUnderlyingNetworkPriority list:"); + pw.println("VcnUnderlyingNetworkTemplate list:"); pw.increaseIndent(); int index = 0; - for (VcnUnderlyingNetworkPriority priority : + for (VcnUnderlyingNetworkTemplate priority : mConnectionConfig.getVcnUnderlyingNetworkPriorities()) { pw.println("Priority index: " + index); priority.dump(pw); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index 27ba854ab1..df2f0d5856 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.vcn.VcnUnderlyingNetworkPriority; +import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -77,7 +77,7 @@ public class UnderlyingNetworkRecord { static Comparator getComparator( VcnContext vcnContext, - LinkedHashSet underlyingNetworkPriorities, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -133,7 +133,7 @@ public class UnderlyingNetworkRecord { void dump( VcnContext vcnContext, IndentingPrintWriter pw, - LinkedHashSet underlyingNetworkPriorities, + LinkedHashSet underlyingNetworkPriorities, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java similarity index 81% rename from Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java rename to Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index 476be44ee7..d03aee282e 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -15,8 +15,8 @@ */ package android.net.vcn; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -27,13 +27,13 @@ import org.junit.Test; import java.util.HashSet; import java.util.Set; -public class VcnCellUnderlyingNetworkPriorityTest { +public class VcnCellUnderlyingNetworkTemplateTest { private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); // Package private for use in VcnGatewayConnectionConfigTest - static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() { - return new VcnCellUnderlyingNetworkPriority.Builder() + static VcnCellUnderlyingNetworkTemplate getTestNetworkPriority() { + return new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setAllowedOperatorPlmnIds(ALLOWED_PLMN_IDS) @@ -45,7 +45,7 @@ public class VcnCellUnderlyingNetworkPriorityTest { @Test public void testBuilderAndGetters() { - final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); assertTrue(networkPriority.allowMetered()); assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedOperatorPlmnIds()); @@ -56,8 +56,8 @@ public class VcnCellUnderlyingNetworkPriorityTest { @Test public void testBuilderAndGettersForDefaultValues() { - final VcnCellUnderlyingNetworkPriority networkPriority = - new VcnCellUnderlyingNetworkPriority.Builder().build(); + final VcnCellUnderlyingNetworkTemplate networkPriority = + new VcnCellUnderlyingNetworkTemplate.Builder().build(); assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); assertFalse(networkPriority.allowMetered()); assertEquals(new HashSet(), networkPriority.getAllowedOperatorPlmnIds()); @@ -68,10 +68,10 @@ public class VcnCellUnderlyingNetworkPriorityTest { @Test public void testPersistableBundle() { - final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); assertEquals( networkPriority, - VcnUnderlyingNetworkPriority.fromPersistableBundle( + VcnUnderlyingNetworkTemplate.fromPersistableBundle( networkPriority.toPersistableBundle())); } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 377f526a98..1f2905da08 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -54,7 +54,7 @@ public class VcnGatewayConnectionConfigTest { }; public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; - private static final LinkedHashSet UNDERLYING_NETWORK_PRIORITIES = + private static final LinkedHashSet UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet(); static { @@ -62,9 +62,9 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(UNDERLYING_CAPS); UNDERLYING_NETWORK_PRIORITIES.add( - VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + VcnCellUnderlyingNetworkTemplateTest.getTestNetworkPriority()); UNDERLYING_NETWORK_PRIORITIES.add( - VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); } public static final long[] RETRY_INTERVALS_MS = @@ -286,7 +286,7 @@ public class VcnGatewayConnectionConfigTest { } private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkPriorities( - LinkedHashSet networkPriorities) { + LinkedHashSet networkPriorities) { return buildTestConfigWithExposedCaps( new VcnGatewayConnectionConfig.Builder( "buildTestConfigWithVcnUnderlyingNetworkPriorities", @@ -300,17 +300,17 @@ public class VcnGatewayConnectionConfigTest { final VcnGatewayConnectionConfig config = buildTestConfigWithVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES); - final LinkedHashSet networkPrioritiesEqual = + final LinkedHashSet networkPrioritiesEqual = new LinkedHashSet(); - networkPrioritiesEqual.add(VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority()); - networkPrioritiesEqual.add(VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + networkPrioritiesEqual.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkPriority()); + networkPrioritiesEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); final VcnGatewayConnectionConfig configEqual = buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesEqual); - final LinkedHashSet networkPrioritiesNotEqual = + final LinkedHashSet networkPrioritiesNotEqual = new LinkedHashSet(); networkPrioritiesNotEqual.add( - VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority()); + VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); final VcnGatewayConnectionConfig configNotEqual = buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesNotEqual); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java similarity index 77% rename from Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java rename to Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java index dd272cb385..652057fd48 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java @@ -15,8 +15,8 @@ */ package android.net.vcn; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -26,13 +26,13 @@ import static org.junit.Assert.fail; import org.junit.Test; -public class VcnWifiUnderlyingNetworkPriorityTest { +public class VcnWifiUnderlyingNetworkTemplateTest { private static final String SSID = "TestWifi"; private static final int INVALID_NETWORK_QUALITY = -1; // Package private for use in VcnGatewayConnectionConfigTest - static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() { - return new VcnWifiUnderlyingNetworkPriority.Builder() + static VcnWifiUnderlyingNetworkTemplate getTestNetworkPriority() { + return new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setSsid(SSID) @@ -41,7 +41,7 @@ public class VcnWifiUnderlyingNetworkPriorityTest { @Test public void testBuilderAndGetters() { - final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); assertTrue(networkPriority.allowMetered()); assertEquals(SSID, networkPriority.getSsid()); @@ -49,8 +49,8 @@ public class VcnWifiUnderlyingNetworkPriorityTest { @Test public void testBuilderAndGettersForDefaultValues() { - final VcnWifiUnderlyingNetworkPriority networkPriority = - new VcnWifiUnderlyingNetworkPriority.Builder().build(); + final VcnWifiUnderlyingNetworkTemplate networkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder().build(); assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); assertFalse(networkPriority.allowMetered()); assertNull(SSID, networkPriority.getSsid()); @@ -59,7 +59,7 @@ public class VcnWifiUnderlyingNetworkPriorityTest { @Test public void testBuildWithInvalidNetworkQuality() { try { - new VcnWifiUnderlyingNetworkPriority.Builder() + new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(INVALID_NETWORK_QUALITY); fail("Expected to fail due to the invalid network quality"); } catch (Exception expected) { @@ -68,10 +68,10 @@ public class VcnWifiUnderlyingNetworkPriorityTest { @Test public void testPersistableBundle() { - final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority(); + final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); assertEquals( networkPriority, - VcnUnderlyingNetworkPriority.fromPersistableBundle( + VcnUnderlyingNetworkTemplate.fromPersistableBundle( networkPriority.toPersistableBundle())); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 46a614f60a..f23d5bf67e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -16,7 +16,7 @@ package com.android.server.vcn.routeselection; -import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY; @@ -39,10 +39,10 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; -import android.net.vcn.VcnCellUnderlyingNetworkPriority; +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; -import android.net.vcn.VcnWifiUnderlyingNetworkPriority; +import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; @@ -142,8 +142,8 @@ public class NetworkPriorityClassifierTest { @Test public void testMatchWithoutNotMeteredBit() { - final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = - new VcnWifiUnderlyingNetworkPriority.Builder() + final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(false /* allowMetered */) .build(); @@ -161,8 +161,8 @@ public class NetworkPriorityClassifierTest { private void verifyMatchWifi( boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) { - final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = - new VcnWifiUnderlyingNetworkPriority.Builder() + final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .build(); @@ -211,8 +211,8 @@ public class NetworkPriorityClassifierTest { private void verifyMatchWifiWithSsid(boolean useMatchedSsid, boolean expectMatch) { final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER; - final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority = - new VcnWifiUnderlyingNetworkPriority.Builder() + final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setSsid(nwPrioritySsid) @@ -237,8 +237,8 @@ public class NetworkPriorityClassifierTest { verifyMatchWifiWithSsid(false /* useMatchedSsid */, false /* expectMatch */); } - private static VcnCellUnderlyingNetworkPriority.Builder getCellNetworkPriorityBuilder() { - return new VcnCellUnderlyingNetworkPriority.Builder() + private static VcnCellUnderlyingNetworkTemplate.Builder getCellNetworkPriorityBuilder() { + return new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) .setAllowMetered(true /* allowMetered */) .setAllowRoaming(true /* allowRoaming */); @@ -257,7 +257,7 @@ public class NetworkPriorityClassifierTest { @Test public void testMatchOpportunisticCell() { - final VcnCellUnderlyingNetworkPriority opportunisticCellNetworkPriority = + final VcnCellUnderlyingNetworkTemplate opportunisticCellNetworkPriority = getCellNetworkPriorityBuilder() .setRequireOpportunistic(true /* requireOpportunistic */) .build(); @@ -277,7 +277,7 @@ public class NetworkPriorityClassifierTest { private void verifyMatchMacroCellWithAllowedPlmnIds( boolean useMatchedPlmnId, boolean expectMatch) { final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER; - final VcnCellUnderlyingNetworkPriority networkPriority = + final VcnCellUnderlyingNetworkTemplate networkPriority = getCellNetworkPriorityBuilder() .setAllowedOperatorPlmnIds(Set.of(networkPriorityPlmnId)) .build(); @@ -306,7 +306,7 @@ public class NetworkPriorityClassifierTest { private void verifyMatchMacroCellWithAllowedSpecificCarrierIds( boolean useMatchedCarrierId, boolean expectMatch) { final int networkPriorityCarrierId = useMatchedCarrierId ? CARRIER_ID : CARRIER_ID_OTHER; - final VcnCellUnderlyingNetworkPriority networkPriority = + final VcnCellUnderlyingNetworkTemplate networkPriority = getCellNetworkPriorityBuilder() .setAllowedSpecificCarrierIds(Set.of(networkPriorityCarrierId)) .build(); @@ -335,7 +335,7 @@ public class NetworkPriorityClassifierTest { @Test public void testMatchWifiFailWithoutNotRoamingBit() { - final VcnCellUnderlyingNetworkPriority networkPriority = + final VcnCellUnderlyingNetworkTemplate networkPriority = getCellNetworkPriorityBuilder().setAllowRoaming(false /* allowRoaming */).build(); assertFalse( From ed1d4defec76bbaf3933c77b7a4ebe63d1d78451 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Dec 2021 18:04:40 -0800 Subject: [PATCH 0296/1057] Update setter/getters to configure underlying network priority - Update setters for configuring meteredness, roaming and opportunistic to take an int instead of a boolean - Update NetworkPriorityClassifier and tests accordingly Bug: 206044122 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: I92bd2831cc42d634d73b842c42d18fa93a4ed46c --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 231 ++++++++++++------ .../net/vcn/VcnGatewayConnectionConfig.java | 135 +++++----- .../net/vcn/VcnUnderlyingNetworkTemplate.java | 162 +++++++----- .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 142 ++++++++--- .../NetworkPriorityClassifier.java | 38 ++- .../UnderlyingNetworkController.java | 6 +- .../UnderlyingNetworkRecord.java | 12 +- .../VcnCellUnderlyingNetworkTemplateTest.java | 41 ++-- .../vcn/VcnGatewayConnectionConfigTest.java | 68 +++--- .../VcnWifiUnderlyingNetworkTemplateTest.java | 24 +- .../NetworkPriorityClassifierTest.java | 25 +- 11 files changed, 549 insertions(+), 335 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 1ac3f0a6d7..2dcb6872d6 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -15,6 +15,9 @@ */ package android.net.vcn; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.getMatchCriteriaString; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; @@ -23,8 +26,12 @@ import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZ import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -37,32 +44,38 @@ import java.util.Collections; import java.util.Objects; import java.util.Set; -// TODO: Add documents -/** @hide */ +/** + * This class represents a configuration for a network template class of underlying cellular + * networks. + * + *

      See {@link VcnUnderlyingNetworkTemplate} + * + * @hide + */ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds"; @NonNull private final Set mAllowedNetworkPlmnIds; private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds"; @NonNull private final Set mAllowedSpecificCarrierIds; - private static final String ALLOW_ROAMING_KEY = "mAllowRoaming"; - private final boolean mAllowRoaming; + private static final String ROAMING_MATCH_KEY = "mRoamingMatchCriteria"; + private final int mRoamingMatchCriteria; - private static final String REQUIRE_OPPORTUNISTIC_KEY = "mRequireOpportunistic"; - private final boolean mRequireOpportunistic; + private static final String OPPORTUNISTIC_MATCH_KEY = "mOpportunisticMatchCriteria"; + private final int mOpportunisticMatchCriteria; private VcnCellUnderlyingNetworkTemplate( int networkQuality, - boolean allowMetered, + int meteredMatchCriteria, Set allowedNetworkPlmnIds, Set allowedSpecificCarrierIds, - boolean allowRoaming, - boolean requireOpportunistic) { - super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, allowMetered); + int roamingMatchCriteria, + int opportunisticMatchCriteria) { + super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, meteredMatchCriteria); mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds); mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds); - mAllowRoaming = allowRoaming; - mRequireOpportunistic = requireOpportunistic; + mRoamingMatchCriteria = roamingMatchCriteria; + mOpportunisticMatchCriteria = opportunisticMatchCriteria; validate(); } @@ -72,15 +85,17 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork protected void validate() { super.validate(); validatePlmnIds(mAllowedNetworkPlmnIds); - Objects.requireNonNull(mAllowedSpecificCarrierIds, "allowedCarrierIds is null"); + Objects.requireNonNull(mAllowedSpecificCarrierIds, "matchingCarrierIds is null"); + validateMatchCriteria(mRoamingMatchCriteria, "mRoamingMatchCriteria"); + validateMatchCriteria(mOpportunisticMatchCriteria, "mOpportunisticMatchCriteria"); } - private static void validatePlmnIds(Set allowedNetworkPlmnIds) { - Objects.requireNonNull(allowedNetworkPlmnIds, "allowedNetworkPlmnIds is null"); + private static void validatePlmnIds(Set matchingOperatorPlmnIds) { + Objects.requireNonNull(matchingOperatorPlmnIds, "matchingOperatorPlmnIds is null"); // A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 decimal // digits. - for (String id : allowedNetworkPlmnIds) { + for (String id : matchingOperatorPlmnIds) { if ((id.length() == 5 || id.length() == 6) && id.matches("[0-9]+")) { continue; } else { @@ -97,7 +112,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork Objects.requireNonNull(in, "PersistableBundle is null"); final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); - final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY); + final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY); final PersistableBundle plmnIdsBundle = in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY); @@ -114,16 +129,16 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork PersistableBundleUtils.toList( specificCarrierIdsBundle, INTEGER_DESERIALIZER)); - final boolean allowRoaming = in.getBoolean(ALLOW_ROAMING_KEY); - final boolean requireOpportunistic = in.getBoolean(REQUIRE_OPPORTUNISTIC_KEY); + final int roamingMatchCriteria = in.getInt(ROAMING_MATCH_KEY); + final int opportunisticMatchCriteria = in.getInt(OPPORTUNISTIC_MATCH_KEY); return new VcnCellUnderlyingNetworkTemplate( networkQuality, - allowMetered, + meteredMatchCriteria, allowedNetworkPlmnIds, allowedSpecificCarrierIds, - allowRoaming, - requireOpportunistic); + roamingMatchCriteria, + opportunisticMatchCriteria); } /** @hide */ @@ -143,35 +158,51 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER); result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle); - result.putBoolean(ALLOW_ROAMING_KEY, mAllowRoaming); - result.putBoolean(REQUIRE_OPPORTUNISTIC_KEY, mRequireOpportunistic); + result.putInt(ROAMING_MATCH_KEY, mRoamingMatchCriteria); + result.putInt(OPPORTUNISTIC_MATCH_KEY, mOpportunisticMatchCriteria); return result; } - /** Retrieve the allowed PLMN IDs, or an empty set if any PLMN ID is acceptable. */ + /** + * Retrieve the matching operator PLMN IDs, or an empty set if any PLMN ID is acceptable. + * + * @see Builder#setOperatorPlmnIds(Set) + */ @NonNull - public Set getAllowedOperatorPlmnIds() { + public Set getOperatorPlmnIds() { return Collections.unmodifiableSet(mAllowedNetworkPlmnIds); } /** - * Retrieve the allowed specific carrier IDs, or an empty set if any specific carrier ID is - * acceptable. + * Retrieve the matching sim specific carrier IDs, or an empty set if any sim specific carrier + * ID is acceptable. + * + * @see Builder#setSimSpecificCarrierIds(Set) */ @NonNull - public Set getAllowedSpecificCarrierIds() { + public Set getSimSpecificCarrierIds() { return Collections.unmodifiableSet(mAllowedSpecificCarrierIds); } - /** Return if roaming is allowed. */ - public boolean allowRoaming() { - return mAllowRoaming; + /** + * Return the matching criteria for roaming networks. + * + * @see Builder#setRoaming(int) + */ + @MatchCriteria + public int getRoaming() { + return mRoamingMatchCriteria; } - /** Return if requiring an opportunistic network. */ - public boolean requireOpportunistic() { - return mRequireOpportunistic; + /** + * Return the matching criteria for opportunistic cellular subscriptions. + * + * @see Builder#setOpportunistic(int) + */ + @MatchCriteria + public int getOpportunistic() { + return mOpportunisticMatchCriteria; } @Override @@ -180,8 +211,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork super.hashCode(), mAllowedNetworkPlmnIds, mAllowedSpecificCarrierIds, - mAllowRoaming, - mRequireOpportunistic); + mRoamingMatchCriteria, + mOpportunisticMatchCriteria); } @Override @@ -197,8 +228,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork final VcnCellUnderlyingNetworkTemplate rhs = (VcnCellUnderlyingNetworkTemplate) other; return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds) && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds) - && mAllowRoaming == rhs.mAllowRoaming - && mRequireOpportunistic == rhs.mRequireOpportunistic; + && mRoamingMatchCriteria == rhs.mRoamingMatchCriteria + && mOpportunisticMatchCriteria == rhs.mOpportunisticMatchCriteria; } /** @hide */ @@ -206,77 +237,125 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork void dumpTransportSpecificFields(IndentingPrintWriter pw) { pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds.toString()); pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds.toString()); - pw.println("mAllowRoaming: " + mAllowRoaming); - pw.println("mRequireOpportunistic: " + mRequireOpportunistic); + pw.println("mRoamingMatchCriteria: " + getMatchCriteriaString(mRoamingMatchCriteria)); + pw.println( + "mOpportunisticMatchCriteria: " + + getMatchCriteriaString(mOpportunisticMatchCriteria)); } - /** This class is used to incrementally build WifiNetworkPriority objects. */ - public static final class Builder extends VcnUnderlyingNetworkTemplate.Builder { + /** This class is used to incrementally build VcnCellUnderlyingNetworkTemplate objects. */ + public static final class Builder { + private int mNetworkQuality = NETWORK_QUALITY_ANY; + private int mMeteredMatchCriteria = MATCH_ANY; + @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); @NonNull private final Set mAllowedSpecificCarrierIds = new ArraySet<>(); - private boolean mAllowRoaming = false; - private boolean mRequireOpportunistic = false; + private int mRoamingMatchCriteria = MATCH_ANY; + private int mOpportunisticMatchCriteria = MATCH_ANY; /** Construct a Builder object. */ public Builder() {} /** - * Set allowed operator PLMN IDs. + * Set the required network quality to match this template. + * + *

      Network quality is a aggregation of multiple signals that reflect the network link + * metrics. For example, the network validation bit (see {@link + * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth + * and signal strength. + * + * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY + * @hide + */ + @NonNull + public Builder setNetworkQuality(@NetworkQuality int networkQuality) { + validateNetworkQuality(networkQuality); + + mNetworkQuality = networkQuality; + return this; + } + + /** + * Set the matching criteria for metered networks. + * + * @param matchCriteria the matching criteria for metered networks. Defaults to {@link + * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} + */ + // The matching getter is defined in the super class. Please see {@link + // VcnUnderlyingNetworkTemplate#getMetered()} + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setMetered(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setMetered"); + + mMeteredMatchCriteria = matchCriteria; + return this; + } + + /** + * Set operator PLMN IDs with which a network can match this template. * *

      This is used to distinguish cases where roaming agreements may dictate a different * priority from a partner's networks. * - * @param allowedNetworkPlmnIds the allowed operator PLMN IDs in String. Defaults to an - * empty set, allowing ANY PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and - * thus consists of 5 or 6 decimal digits. See {@link SubscriptionInfo#getMccString()} - * and {@link SubscriptionInfo#getMncString()}. + * @param operatorPlmnIds the matching operator PLMN IDs in String. Network with one of the + * matching PLMN IDs can match this template. Defaults to an empty set, allowing ANY + * PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 + * decimal digits. See {@link SubscriptionInfo#getMccString()} and {@link + * SubscriptionInfo#getMncString()}. */ @NonNull - public Builder setAllowedOperatorPlmnIds(@NonNull Set allowedNetworkPlmnIds) { - validatePlmnIds(allowedNetworkPlmnIds); + public Builder setOperatorPlmnIds(@NonNull Set operatorPlmnIds) { + validatePlmnIds(operatorPlmnIds); mAllowedNetworkPlmnIds.clear(); - mAllowedNetworkPlmnIds.addAll(allowedNetworkPlmnIds); + mAllowedNetworkPlmnIds.addAll(operatorPlmnIds); return this; } /** - * Set allowed specific carrier IDs. + * Set sim specific carrier IDs with which a network can match this template. * - * @param allowedSpecificCarrierIds the allowed specific carrier IDs. Defaults to an empty - * set, allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}. + * @param simSpecificCarrierIds the matching sim specific carrier IDs. Network with one of + * the sim specific carrier IDs can match this template. Defaults to an empty set, + * allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}. */ @NonNull - public Builder setAllowedSpecificCarrierIds( - @NonNull Set allowedSpecificCarrierIds) { - Objects.requireNonNull(allowedSpecificCarrierIds, "allowedCarrierIds is null"); + public Builder setSimSpecificCarrierIds(@NonNull Set simSpecificCarrierIds) { + Objects.requireNonNull(simSpecificCarrierIds, "simSpecificCarrierIds is null"); + mAllowedSpecificCarrierIds.clear(); - mAllowedSpecificCarrierIds.addAll(allowedSpecificCarrierIds); + mAllowedSpecificCarrierIds.addAll(simSpecificCarrierIds); return this; } /** - * Set if roaming is allowed. + * Set the matching criteria for roaming networks. * - * @param allowRoaming the flag to indicate if roaming is allowed. Defaults to {@code - * false}. + * @param matchCriteria the matching criteria for roaming networks. Defaults to {@link + * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}. */ @NonNull - public Builder setAllowRoaming(boolean allowRoaming) { - mAllowRoaming = allowRoaming; + public Builder setRoaming(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setRoaming"); + + mRoamingMatchCriteria = matchCriteria; return this; } /** - * Set if requiring an opportunistic network. + * Set the matching criteria for opportunistic cellular subscriptions. * - * @param requireOpportunistic the flag to indicate if caller requires an opportunistic - * network. Defaults to {@code false}. + * @param matchCriteria the matching criteria for opportunistic cellular subscriptions. + * Defaults to {@link #MATCH_ANY}. See {@link + * SubscriptionManager#setOpportunistic(boolean, int)} */ @NonNull - public Builder setRequireOpportunistic(boolean requireOpportunistic) { - mRequireOpportunistic = requireOpportunistic; + public Builder setOpportunistic(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setOpportunistic"); + + mOpportunisticMatchCriteria = matchCriteria; return this; } @@ -285,17 +364,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork public VcnCellUnderlyingNetworkTemplate build() { return new VcnCellUnderlyingNetworkTemplate( mNetworkQuality, - mAllowMetered, + mMeteredMatchCriteria, mAllowedNetworkPlmnIds, mAllowedSpecificCarrierIds, - mAllowRoaming, - mRequireOpportunistic); - } - - /** @hide */ - @Override - Builder self() { - return this; + mRoamingMatchCriteria, + mOpportunisticMatchCriteria); } } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index d07c24a652..f17f30a0d1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.internal.annotations.VisibleForTesting.Visibility; @@ -42,7 +43,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.SortedSet; @@ -162,30 +163,24 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) - public static final LinkedHashSet - DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>(); + public static final List DEFAULT_UNDERLYING_NETWORK_TEMPLATES = + new ArrayList<>(); static { - DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setAllowRoaming(true /* allowRoaming */) - .setRequireOpportunistic(true /* requireOpportunistic */) + .setOpportunistic(MATCH_REQUIRED) .build()); - DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) .build()); - DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add( + DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setAllowRoaming(true /* allowRoaming */) - .setRequireOpportunistic(false /* requireOpportunistic */) .build()); } @@ -200,9 +195,9 @@ public final class VcnGatewayConnectionConfig { /** @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) - public static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities"; + public static final String UNDERLYING_NETWORK_TEMPLATES_KEY = "mUnderlyingNetworkTemplates"; - @NonNull private final LinkedHashSet mUnderlyingNetworkPriorities; + @NonNull private final List mUnderlyingNetworkTemplates; private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -215,7 +210,7 @@ public final class VcnGatewayConnectionConfig { @NonNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set exposedCapabilities, - @NonNull LinkedHashSet underlyingNetworkPriorities, + @NonNull List underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; @@ -224,9 +219,9 @@ public final class VcnGatewayConnectionConfig { mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; - mUnderlyingNetworkPriorities = new LinkedHashSet<>(underlyingNetworkPriorities); - if (mUnderlyingNetworkPriorities.isEmpty()) { - mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); + if (mUnderlyingNetworkTemplates.isEmpty()) { + mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } validate(); @@ -250,22 +245,19 @@ public final class VcnGatewayConnectionConfig { mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - final PersistableBundle networkPrioritiesBundle = - in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY); + final PersistableBundle networkTemplatesBundle = + in.getPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY); - if (networkPrioritiesBundle == null) { - // UNDERLYING_NETWORK_PRIORITIES_KEY was added in Android T. Thus + if (networkTemplatesBundle == null) { + // UNDERLYING_NETWORK_TEMPLATES_KEY was added in Android T. Thus // VcnGatewayConnectionConfig created on old platforms will not have this data and will // be assigned with the default value - mUnderlyingNetworkPriorities = - new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); - + mUnderlyingNetworkTemplates = new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } else { - mUnderlyingNetworkPriorities = - new LinkedHashSet<>( - PersistableBundleUtils.toList( - networkPrioritiesBundle, - VcnUnderlyingNetworkTemplate::fromPersistableBundle)); + mUnderlyingNetworkTemplates = + PersistableBundleUtils.toList( + networkTemplatesBundle, + VcnUnderlyingNetworkTemplate::fromPersistableBundle); } mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); @@ -285,7 +277,7 @@ public final class VcnGatewayConnectionConfig { checkValidCapability(cap); } - Objects.requireNonNull(mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null"); + validateNetworkTemplateList(mUnderlyingNetworkTemplates); Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); validateRetryInterval(mRetryIntervalsMs); @@ -314,6 +306,19 @@ public final class VcnGatewayConnectionConfig { } } + private static void validateNetworkTemplateList( + List networkPriorityRules) { + Objects.requireNonNull(networkPriorityRules, "networkPriorityRules is null"); + + Set existingRules = new ArraySet<>(); + for (VcnUnderlyingNetworkTemplate rule : networkPriorityRules) { + Objects.requireNonNull(rule, "Found null value VcnUnderlyingNetworkTemplate"); + if (!existingRules.add(rule)) { + throw new IllegalArgumentException("Found duplicate VcnUnderlyingNetworkTemplate"); + } + } + } + /** * Returns the configured Gateway Connection name. * @@ -368,15 +373,14 @@ public final class VcnGatewayConnectionConfig { } /** - * Retrieve the configured VcnUnderlyingNetworkTemplate list, or a default list if it is not - * configured. + * Retrieve the VcnUnderlyingNetworkTemplate list, or a default list if it is not configured. * - * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet) + * @see Builder#setVcnUnderlyingNetworkTemplates(List) * @hide */ @NonNull - public LinkedHashSet getVcnUnderlyingNetworkPriorities() { - return new LinkedHashSet<>(mUnderlyingNetworkPriorities); + public List getVcnUnderlyingNetworkTemplates() { + return new ArrayList<>(mUnderlyingNetworkTemplates); } /** @@ -415,15 +419,15 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); - final PersistableBundle networkPrioritiesBundle = + final PersistableBundle networkTemplatesBundle = PersistableBundleUtils.fromList( - new ArrayList<>(mUnderlyingNetworkPriorities), + mUnderlyingNetworkTemplates, VcnUnderlyingNetworkTemplate::toPersistableBundle); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); - result.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, networkPrioritiesBundle); + result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -436,7 +440,7 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, - mUnderlyingNetworkPriorities, + mUnderlyingNetworkTemplates, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); } @@ -451,7 +455,7 @@ public final class VcnGatewayConnectionConfig { return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams) && mExposedCapabilities.equals(rhs.mExposedCapabilities) - && mUnderlyingNetworkPriorities.equals(rhs.mUnderlyingNetworkPriorities) + && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; } @@ -465,8 +469,8 @@ public final class VcnGatewayConnectionConfig { @NonNull private final Set mExposedCapabilities = new ArraySet(); @NonNull - private final LinkedHashSet mUnderlyingNetworkPriorities = - new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + private final List mUnderlyingNetworkTemplates = + new ArrayList<>(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; @@ -539,27 +543,38 @@ public final class VcnGatewayConnectionConfig { } /** - * Set the VcnUnderlyingNetworkTemplate list. + * Set the list of templates to match underlying networks against, in priority order. * - * @param underlyingNetworkPriorities a list of unique VcnUnderlyingNetworkPriorities that - * are ordered from most to least preferred, or an empty list to use the default - * prioritization. The default network prioritization is Opportunistic cellular, Carrier - * WiFi and Macro cellular - * @return + *

      To select the VCN underlying network, the VCN gateway will go through all the network + * candidates and return a network matching the highest priority rule. + * + *

      If multiple networks match the same rule, the VCN will prefer an already-selected + * network as opposed to a new/unselected network. However, if both are new/unselected + * networks, a network will be chosen arbitrarily amongst the networks matching the highest + * priority rule. + * + *

      A rule that matches all carrier-owned networks is implicitly added at the end of the + * priority list, ensuring that if all networks fail to match the rules provided, an + * underlying network will still be selected (at random if necessary). + * + * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are + * ordered from most to least preferred, or an empty list to use the default + * prioritization. The default network prioritization order is Opportunistic cellular, + * Carrier WiFi and then Macro cellular. + * @return this {@link Builder} instance, for chaining + * @hide */ - /** @hide */ @NonNull - public Builder setVcnUnderlyingNetworkPriorities( - @NonNull LinkedHashSet underlyingNetworkPriorities) { - Objects.requireNonNull( - mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null"); + public Builder setVcnUnderlyingNetworkTemplates( + @NonNull List underlyingNetworkTemplates) { + validateNetworkTemplateList(underlyingNetworkTemplates); - mUnderlyingNetworkPriorities.clear(); + mUnderlyingNetworkTemplates.clear(); - if (underlyingNetworkPriorities.isEmpty()) { - mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES); + if (underlyingNetworkTemplates.isEmpty()) { + mUnderlyingNetworkTemplates.addAll(DEFAULT_UNDERLYING_NETWORK_TEMPLATES); } else { - mUnderlyingNetworkPriorities.addAll(underlyingNetworkPriorities); + mUnderlyingNetworkTemplates.addAll(underlyingNetworkTemplates); } return this; @@ -629,7 +644,7 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, - mUnderlyingNetworkPriorities, + mUnderlyingNetworkTemplates, mRetryIntervalsMs, mMaxMtu); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index d306d5cb68..33b02e8f10 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -15,11 +15,14 @@ */ package android.net.vcn; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.os.PersistableBundle; import android.util.SparseArray; @@ -31,17 +34,26 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; -// TODO: Add documents -/** @hide */ +/** + * This class represents a template containing set of underlying network requirements for doing + * route selection. + * + *

      Apps provisioning a VCN can configure the underlying network priority for each Gateway + * Connection by setting a list (in priority order, most to least preferred) of the appropriate + * subclasses in the VcnGatewayConnectionConfig. See {@link + * VcnGatewayConnectionConfig.Builder#setVcnUnderlyingNetworkTemplates} + * + * @hide + */ public abstract class VcnUnderlyingNetworkTemplate { /** @hide */ - protected static final int NETWORK_PRIORITY_TYPE_WIFI = 1; + static final int NETWORK_PRIORITY_TYPE_WIFI = 1; /** @hide */ - protected static final int NETWORK_PRIORITY_TYPE_CELL = 2; + static final int NETWORK_PRIORITY_TYPE_CELL = 2; - /** Denotes that any network quality is acceptable */ + /** Denotes that any network quality is acceptable. @hide */ public static final int NETWORK_QUALITY_ANY = 0; - /** Denotes that network quality needs to be OK */ + /** Denotes that network quality needs to be OK. @hide */ public static final int NETWORK_QUALITY_OK = 100000; private static final SparseArray NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>(); @@ -56,34 +68,81 @@ public abstract class VcnUnderlyingNetworkTemplate { @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY}) public @interface NetworkQuality {} + /** + * Used to configure the matching criteria of a network capability (See {@link + * NetworkCapabilities}). Denotes that networks with or without the capability are both + * acceptable to match the template. + */ + public static final int MATCH_ANY = 0; + + /** + * Used to configure the matching criteria of a network capability (See {@link + * NetworkCapabilities}). Denotes that only network with the capability can match the template. + */ + public static final int MATCH_REQUIRED = 1; + + /** + * Used to configure the matching criteria of a network capability (See {@link + * NetworkCapabilities}). Denotes that only network without the capability can match the + * template. + */ + public static final int MATCH_FORBIDDEN = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({MATCH_ANY, MATCH_REQUIRED, MATCH_FORBIDDEN}) + public @interface MatchCriteria {} + + private static final SparseArray MATCH_CRITERIA_TO_STRING_MAP = new SparseArray<>(); + + static { + MATCH_CRITERIA_TO_STRING_MAP.put(MATCH_ANY, "MATCH_ANY"); + MATCH_CRITERIA_TO_STRING_MAP.put(MATCH_REQUIRED, "MATCH_REQUIRED"); + MATCH_CRITERIA_TO_STRING_MAP.put(MATCH_FORBIDDEN, "MATCH_FORBIDDEN"); + } + private static final String NETWORK_PRIORITY_TYPE_KEY = "mNetworkPriorityType"; private final int mNetworkPriorityType; /** @hide */ - protected static final String NETWORK_QUALITY_KEY = "mNetworkQuality"; + static final String NETWORK_QUALITY_KEY = "mNetworkQuality"; + private final int mNetworkQuality; /** @hide */ - protected static final String ALLOW_METERED_KEY = "mAllowMetered"; - private final boolean mAllowMetered; + static final String METERED_MATCH_KEY = "mMeteredMatchCriteria"; + + private final int mMeteredMatchCriteria; /** @hide */ - protected VcnUnderlyingNetworkTemplate( - int networkPriorityType, int networkQuality, boolean allowMetered) { + VcnUnderlyingNetworkTemplate( + int networkPriorityType, int networkQuality, int meteredMatchCriteria) { mNetworkPriorityType = networkPriorityType; mNetworkQuality = networkQuality; - mAllowMetered = allowMetered; + mMeteredMatchCriteria = meteredMatchCriteria; } - private static void validateNetworkQuality(int networkQuality) { + /** @hide */ + static void validateNetworkQuality(int networkQuality) { Preconditions.checkArgument( networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK, "Invalid networkQuality:" + networkQuality); } + /** @hide */ + static void validateMatchCriteria(int meteredMatchCriteria, String matchingCapability) { + Preconditions.checkArgument( + MATCH_CRITERIA_TO_STRING_MAP.contains(meteredMatchCriteria), + "Invalid matching criteria: " + + meteredMatchCriteria + + " for " + + matchingCapability); + } + /** @hide */ protected void validate() { validateNetworkQuality(mNetworkQuality); + validateMatchCriteria(mMeteredMatchCriteria, "mMeteredMatchCriteria"); } /** @hide */ @@ -112,14 +171,14 @@ public abstract class VcnUnderlyingNetworkTemplate { result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType); result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality); - result.putBoolean(ALLOW_METERED_KEY, mAllowMetered); + result.putInt(METERED_MATCH_KEY, mMeteredMatchCriteria); return result; } @Override public int hashCode() { - return Objects.hash(mNetworkPriorityType, mNetworkQuality, mAllowMetered); + return Objects.hash(mNetworkPriorityType, mNetworkQuality, mMeteredMatchCriteria); } @Override @@ -131,7 +190,17 @@ public abstract class VcnUnderlyingNetworkTemplate { final VcnUnderlyingNetworkTemplate rhs = (VcnUnderlyingNetworkTemplate) other; return mNetworkPriorityType == rhs.mNetworkPriorityType && mNetworkQuality == rhs.mNetworkQuality - && mAllowMetered == rhs.mAllowMetered; + && mMeteredMatchCriteria == rhs.mMeteredMatchCriteria; + } + + /** @hide */ + static String getNameString(SparseArray toStringMap, int key) { + return toStringMap.get(key, "Invalid value " + key); + } + + /** @hide */ + static String getMatchCriteriaString(int meteredMatchCriteria) { + return getNameString(MATCH_CRITERIA_TO_STRING_MAP, meteredMatchCriteria); } /** @hide */ @@ -148,65 +217,32 @@ public abstract class VcnUnderlyingNetworkTemplate { pw.println( "mNetworkQuality: " - + NETWORK_QUALITY_TO_STRING_MAP.get( - mNetworkQuality, "Invalid value " + mNetworkQuality)); - pw.println("mAllowMetered: " + mAllowMetered); + + getNameString(NETWORK_QUALITY_TO_STRING_MAP, mNetworkQuality)); + pw.println("mMeteredMatchCriteria: " + getMatchCriteriaString(mMeteredMatchCriteria)); dumpTransportSpecificFields(pw); pw.decreaseIndent(); } - /** Retrieve the required network quality. */ + /** + * Retrieve the required network quality to match this template. + * + * @see Builder#setNetworkQuality(int) + * @hide + */ @NetworkQuality public int getNetworkQuality() { return mNetworkQuality; } - /** Return if a metered network is allowed. */ - public boolean allowMetered() { - return mAllowMetered; - } - /** - * This class is used to incrementally build VcnUnderlyingNetworkTemplate objects. + * Return the matching criteria for metered networks. * - * @param The subclass to be built. + * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMetered(int) + * @see VcnCellUnderlyingNetworkTemplate.Builder#setMetered(int) */ - public abstract static class Builder> { - /** @hide */ - protected int mNetworkQuality = NETWORK_QUALITY_ANY; - /** @hide */ - protected boolean mAllowMetered = false; - - /** @hide */ - protected Builder() {} - - /** - * Set the required network quality. - * - * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY - */ - @NonNull - public T setNetworkQuality(@NetworkQuality int networkQuality) { - validateNetworkQuality(networkQuality); - - mNetworkQuality = networkQuality; - return self(); - } - - /** - * Set if a metered network is allowed. - * - * @param allowMetered the flag to indicate if a metered network is allowed, defaults to - * {@code false} - */ - @NonNull - public T setAllowMetered(boolean allowMetered) { - mAllowMetered = allowMetered; - return self(); - } - - /** @hide */ - abstract T self(); + @MatchCriteria + public int getMetered() { + return mMeteredMatchCriteria; } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 6bbb2bfecd..fcf5b09430 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -16,30 +16,60 @@ package android.net.vcn; import static com.android.internal.annotations.VisibleForTesting.Visibility; +import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; +import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.net.NetworkCapabilities; import android.os.PersistableBundle; +import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.vcn.util.PersistableBundleUtils; +import java.util.ArrayList; +import java.util.Collections; import java.util.Objects; +import java.util.Set; -// TODO: Add documents -/** @hide */ +/** + * This class represents a configuration for a network template class of underlying Carrier WiFi + * networks. + * + *

      See {@link VcnUnderlyingNetworkTemplate} + * + * @hide + */ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { - private static final String SSID_KEY = "mSsid"; - @Nullable private final String mSsid; + private static final String SSIDS_KEY = "mSsids"; + @Nullable private final Set mSsids; private VcnWifiUnderlyingNetworkTemplate( - int networkQuality, boolean allowMetered, String ssid) { - super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, allowMetered); - mSsid = ssid; + int networkQuality, int meteredMatchCriteria, Set ssids) { + super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, meteredMatchCriteria); + mSsids = new ArraySet<>(ssids); validate(); } + /** @hide */ + @Override + protected void validate() { + super.validate(); + validateSsids(mSsids); + } + + private static void validateSsids(Set ssids) { + Objects.requireNonNull(ssids, "ssids is null"); + + for (String ssid : ssids) { + Objects.requireNonNull(ssid, "found null value ssid"); + } + } + /** @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) @@ -48,9 +78,14 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork Objects.requireNonNull(in, "PersistableBundle is null"); final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); - final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY); - final String ssid = in.getString(SSID_KEY); - return new VcnWifiUnderlyingNetworkTemplate(networkQuality, allowMetered, ssid); + final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY); + + final PersistableBundle ssidsBundle = in.getPersistableBundle(SSIDS_KEY); + Objects.requireNonNull(ssidsBundle, "ssidsBundle is null"); + final Set ssids = + new ArraySet( + PersistableBundleUtils.toList(ssidsBundle, STRING_DESERIALIZER)); + return new VcnWifiUnderlyingNetworkTemplate(networkQuality, meteredMatchCriteria, ssids); } /** @hide */ @@ -59,13 +94,17 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @VisibleForTesting(visibility = Visibility.PROTECTED) public PersistableBundle toPersistableBundle() { final PersistableBundle result = super.toPersistableBundle(); - result.putString(SSID_KEY, mSsid); + + final PersistableBundle ssidsBundle = + PersistableBundleUtils.fromList(new ArrayList<>(mSsids), STRING_SERIALIZER); + result.putPersistableBundle(SSIDS_KEY, ssidsBundle); + return result; } @Override public int hashCode() { - return Objects.hash(super.hashCode(), mSsid); + return Objects.hash(super.hashCode(), mSsids); } @Override @@ -79,49 +118,90 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } final VcnWifiUnderlyingNetworkTemplate rhs = (VcnWifiUnderlyingNetworkTemplate) other; - return mSsid.equals(rhs.mSsid); + return mSsids.equals(rhs.mSsids); } /** @hide */ @Override void dumpTransportSpecificFields(IndentingPrintWriter pw) { - pw.println("mSsid: " + mSsid); + pw.println("mSsids: " + mSsids); } - /** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */ - @Nullable - public String getSsid() { - return mSsid; + /** + * Retrieve the matching SSIDs, or an empty set if any SSID is acceptable. + * + * @see Builder#setSsids(Set) + */ + @NonNull + public Set getSsids() { + return Collections.unmodifiableSet(mSsids); } /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ - public static class Builder extends VcnUnderlyingNetworkTemplate.Builder { - @Nullable private String mSsid; + public static final class Builder { + private int mNetworkQuality = NETWORK_QUALITY_ANY; + private int mMeteredMatchCriteria = MATCH_ANY; + @NonNull private final Set mSsids = new ArraySet<>(); /** Construct a Builder object. */ public Builder() {} /** - * Set the required SSID. + * Set the required network quality to match this template. * - * @param ssid the required SSID, or {@code null} if any SSID is acceptable. + *

      Network quality is a aggregation of multiple signals that reflect the network link + * metrics. For example, the network validation bit (see {@link + * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth + * and signal strength. + * + * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY + * @hide */ @NonNull - public Builder setSsid(@Nullable String ssid) { - mSsid = ssid; + public Builder setNetworkQuality(@NetworkQuality int networkQuality) { + validateNetworkQuality(networkQuality); + + mNetworkQuality = networkQuality; + return this; + } + + /** + * Set the matching criteria for metered networks. + * + * @param matchCriteria the matching criteria for metered networks. Defaults to {@link + * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} + */ + // The matching getter is defined in the super class. Please see {@link + // VcnUnderlyingNetworkTemplate#getMetered()} + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setMetered(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setMetered"); + + mMeteredMatchCriteria = matchCriteria; + return this; + } + + /** + * Set the SSIDs with which a network can match this priority rule. + * + * @param ssids the matching SSIDs. Network with one of the matching SSIDs can match this + * priority rule. Defaults to an empty set, allowing ANY SSID. + */ + @NonNull + public Builder setSsids(@NonNull Set ssids) { + validateSsids(ssids); + + mSsids.clear(); + mSsids.addAll(ssids); return this; } /** Build the VcnWifiUnderlyingNetworkTemplate. */ @NonNull public VcnWifiUnderlyingNetworkTemplate build() { - return new VcnWifiUnderlyingNetworkTemplate(mNetworkQuality, mAllowMetered, mSsid); - } - - /** @hide */ - @Override - Builder self() { - return this; + return new VcnWifiUnderlyingNetworkTemplate( + mNetworkQuality, mMeteredMatchCriteria, mSsids); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index bd8d13b871..6db25b7ed5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -20,6 +20,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; @@ -44,7 +46,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; /** @hide */ @@ -76,7 +78,7 @@ class NetworkPriorityClassifier { public static int calculatePriorityClass( VcnContext vcnContext, UnderlyingNetworkRecord networkRecord, - LinkedHashSet underlyingNetworkPriorities, + List underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -94,7 +96,7 @@ class NetworkPriorityClassifier { } int priorityIndex = 0; - for (VcnUnderlyingNetworkTemplate nwPriority : underlyingNetworkPriorities) { + for (VcnUnderlyingNetworkTemplate nwPriority : underlyingNetworkTemplates) { if (checkMatchesPriorityRule( vcnContext, nwPriority, @@ -122,7 +124,11 @@ class NetworkPriorityClassifier { // TODO: Check Network Quality reported by metric monitors/probers. final NetworkCapabilities caps = networkRecord.networkCapabilities; - if (!networkPriority.allowMetered() && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)) { + + final int meteredMatch = networkPriority.getMetered(); + final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED); + if (meteredMatch == MATCH_REQUIRED && !isMetered + || meteredMatch == MATCH_FORBIDDEN && isMetered) { return false; } @@ -171,7 +177,8 @@ class NetworkPriorityClassifier { return false; } - if (networkPriority.getSsid() != null && networkPriority.getSsid() != caps.getSsid()) { + if (!networkPriority.getSsids().isEmpty() + && !networkPriority.getSsids().contains(caps.getSsid())) { return false; } @@ -226,26 +233,31 @@ class NetworkPriorityClassifier { .getSystemService(TelephonyManager.class) .createForSubscriptionId(subId); - if (!networkPriority.getAllowedOperatorPlmnIds().isEmpty()) { + if (!networkPriority.getOperatorPlmnIds().isEmpty()) { final String plmnId = subIdSpecificTelephonyMgr.getNetworkOperator(); - if (!networkPriority.getAllowedOperatorPlmnIds().contains(plmnId)) { + if (!networkPriority.getOperatorPlmnIds().contains(plmnId)) { return false; } } - if (!networkPriority.getAllowedSpecificCarrierIds().isEmpty()) { + if (!networkPriority.getSimSpecificCarrierIds().isEmpty()) { final int carrierId = subIdSpecificTelephonyMgr.getSimSpecificCarrierId(); - if (!networkPriority.getAllowedSpecificCarrierIds().contains(carrierId)) { + if (!networkPriority.getSimSpecificCarrierIds().contains(carrierId)) { return false; } } - if (!networkPriority.allowRoaming() && !caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)) { + final int roamingMatch = networkPriority.getRoaming(); + final boolean isRoaming = !caps.hasCapability(NET_CAPABILITY_NOT_ROAMING); + if (roamingMatch == MATCH_REQUIRED && !isRoaming + || roamingMatch == MATCH_FORBIDDEN && isRoaming) { return false; } - if (networkPriority.requireOpportunistic()) { - if (!isOpportunistic(snapshot, caps.getSubscriptionIds())) { + final int opportunisticMatch = networkPriority.getOpportunistic(); + final boolean isOpportunistic = isOpportunistic(snapshot, caps.getSubscriptionIds()); + if (opportunisticMatch == MATCH_REQUIRED) { + if (!isOpportunistic) { return false; } @@ -265,6 +277,8 @@ class NetworkPriorityClassifier { .contains(SubscriptionManager.getActiveDataSubscriptionId())) { return false; } + } else if (opportunisticMatch == MATCH_FORBIDDEN && !isOpportunistic) { + return false; } return true; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index ca2e449ffc..6933e6641d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -401,7 +401,7 @@ public class UnderlyingNetworkController { new TreeSet<>( UnderlyingNetworkRecord.getComparator( mVcnContext, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mConnectionConfig.getVcnUnderlyingNetworkTemplates(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, @@ -502,7 +502,7 @@ public class UnderlyingNetworkController { pw.increaseIndent(); int index = 0; for (VcnUnderlyingNetworkTemplate priority : - mConnectionConfig.getVcnUnderlyingNetworkPriorities()) { + mConnectionConfig.getVcnUnderlyingNetworkTemplates()) { pw.println("Priority index: " + index); priority.dump(pw); index++; @@ -518,7 +518,7 @@ public class UnderlyingNetworkController { record.dump( mVcnContext, pw, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mConnectionConfig.getVcnUnderlyingNetworkTemplates(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index df2f0d5856..c0488b18cb 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -32,7 +32,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.VcnContext; import java.util.Comparator; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Objects; /** @@ -77,7 +77,7 @@ public class UnderlyingNetworkRecord { static Comparator getComparator( VcnContext vcnContext, - LinkedHashSet underlyingNetworkPriorities, + List underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -87,7 +87,7 @@ public class UnderlyingNetworkRecord { NetworkPriorityClassifier.calculatePriorityClass( vcnContext, left, - underlyingNetworkPriorities, + underlyingNetworkTemplates, subscriptionGroup, snapshot, currentlySelected, @@ -96,7 +96,7 @@ public class UnderlyingNetworkRecord { NetworkPriorityClassifier.calculatePriorityClass( vcnContext, right, - underlyingNetworkPriorities, + underlyingNetworkTemplates, subscriptionGroup, snapshot, currentlySelected, @@ -133,7 +133,7 @@ public class UnderlyingNetworkRecord { void dump( VcnContext vcnContext, IndentingPrintWriter pw, - LinkedHashSet underlyingNetworkPriorities, + List underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, @@ -145,7 +145,7 @@ public class UnderlyingNetworkRecord { NetworkPriorityClassifier.calculatePriorityClass( vcnContext, this, - underlyingNetworkPriorities, + underlyingNetworkTemplates, subscriptionGroup, snapshot, currentlySelected, diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index d03aee282e..4a724b72f5 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -15,12 +15,13 @@ */ package android.net.vcn; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -32,26 +33,26 @@ public class VcnCellUnderlyingNetworkTemplateTest { private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); // Package private for use in VcnGatewayConnectionConfigTest - static VcnCellUnderlyingNetworkTemplate getTestNetworkPriority() { + static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { return new VcnCellUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setAllowedOperatorPlmnIds(ALLOWED_PLMN_IDS) - .setAllowedSpecificCarrierIds(ALLOWED_CARRIER_IDS) - .setAllowRoaming(true /* allowRoaming */) - .setRequireOpportunistic(true /* requireOpportunistic */) + .setMetered(MATCH_FORBIDDEN) + .setOperatorPlmnIds(ALLOWED_PLMN_IDS) + .setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS) + .setRoaming(MATCH_FORBIDDEN) + .setOpportunistic(MATCH_REQUIRED) .build(); } @Test public void testBuilderAndGetters() { - final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); + final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); - assertTrue(networkPriority.allowMetered()); - assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedOperatorPlmnIds()); - assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getAllowedSpecificCarrierIds()); - assertTrue(networkPriority.allowRoaming()); - assertTrue(networkPriority.requireOpportunistic()); + assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered()); + assertEquals(ALLOWED_PLMN_IDS, networkPriority.getOperatorPlmnIds()); + assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getSimSpecificCarrierIds()); + assertEquals(MATCH_FORBIDDEN, networkPriority.getRoaming()); + assertEquals(MATCH_REQUIRED, networkPriority.getOpportunistic()); } @Test @@ -59,16 +60,16 @@ public class VcnCellUnderlyingNetworkTemplateTest { final VcnCellUnderlyingNetworkTemplate networkPriority = new VcnCellUnderlyingNetworkTemplate.Builder().build(); assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); - assertFalse(networkPriority.allowMetered()); - assertEquals(new HashSet(), networkPriority.getAllowedOperatorPlmnIds()); - assertEquals(new HashSet(), networkPriority.getAllowedSpecificCarrierIds()); - assertFalse(networkPriority.allowRoaming()); - assertFalse(networkPriority.requireOpportunistic()); + assertEquals(MATCH_ANY, networkPriority.getMetered()); + assertEquals(new HashSet(), networkPriority.getOperatorPlmnIds()); + assertEquals(new HashSet(), networkPriority.getSimSpecificCarrierIds()); + assertEquals(MATCH_ANY, networkPriority.getRoaming()); + assertEquals(MATCH_ANY, networkPriority.getOpportunistic()); } @Test public void testPersistableBundle() { - final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); + final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); assertEquals( networkPriority, VcnUnderlyingNetworkTemplate.fromPersistableBundle( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 1f2905da08..d7884e40b4 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -17,8 +17,8 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; -import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES; -import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_PRIORITIES_KEY; +import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES; +import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_TEMPLATES_KEY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -40,8 +40,9 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashSet; +import java.util.List; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -54,17 +55,17 @@ public class VcnGatewayConnectionConfigTest { }; public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; - private static final LinkedHashSet UNDERLYING_NETWORK_PRIORITIES = - new LinkedHashSet(); + private static final List UNDERLYING_NETWORK_TEMPLATES = + new ArrayList(); static { Arrays.sort(EXPOSED_CAPS); Arrays.sort(UNDERLYING_CAPS); - UNDERLYING_NETWORK_PRIORITIES.add( - VcnCellUnderlyingNetworkTemplateTest.getTestNetworkPriority()); - UNDERLYING_NETWORK_PRIORITIES.add( - VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); + UNDERLYING_NETWORK_TEMPLATES.add( + VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); + UNDERLYING_NETWORK_TEMPLATES.add( + VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); } public static final long[] RETRY_INTERVALS_MS = @@ -95,7 +96,7 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES); + newBuilder().setVcnUnderlyingNetworkTemplates(UNDERLYING_NETWORK_TEMPLATES); return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS); } @@ -174,10 +175,10 @@ public class VcnGatewayConnectionConfigTest { } @Test - public void testBuilderRequiresNonNullNetworkPriorities() { + public void testBuilderRequiresNonNullNetworkTemplates() { try { - newBuilder().setVcnUnderlyingNetworkPriorities(null); - fail("Expected exception due to invalid underlyingNetworkPriorities"); + newBuilder().setVcnUnderlyingNetworkTemplates(null); + fail("Expected exception due to invalid underlyingNetworkTemplates"); } catch (NullPointerException e) { } } @@ -219,7 +220,7 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); - assertEquals(UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities()); + assertEquals(UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkTemplates()); assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); @@ -234,13 +235,13 @@ public class VcnGatewayConnectionConfigTest { } @Test - public void testParsePersistableBundleWithoutVcnUnderlyingNetworkPriorities() { + public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() { PersistableBundle configBundle = buildTestConfig().toPersistableBundle(); - configBundle.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, null); + configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null); final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle); assertEquals( - DEFAULT_UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities()); + DEFAULT_UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkTemplates()); } private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) { @@ -285,39 +286,36 @@ public class VcnGatewayConnectionConfigTest { assertNotEquals(config, anotherConfig); } - private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkPriorities( - LinkedHashSet networkPriorities) { + private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkTemplates( + List networkTemplates) { return buildTestConfigWithExposedCaps( new VcnGatewayConnectionConfig.Builder( - "buildTestConfigWithVcnUnderlyingNetworkPriorities", + "buildTestConfigWithVcnUnderlyingNetworkTemplates", TUNNEL_CONNECTION_PARAMS) - .setVcnUnderlyingNetworkPriorities(networkPriorities), + .setVcnUnderlyingNetworkTemplates(networkTemplates), EXPOSED_CAPS); } @Test - public void testVcnUnderlyingNetworkPrioritiesEquality() throws Exception { + public void testVcnUnderlyingNetworkTemplatesEquality() throws Exception { final VcnGatewayConnectionConfig config = - buildTestConfigWithVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES); + buildTestConfigWithVcnUnderlyingNetworkTemplates(UNDERLYING_NETWORK_TEMPLATES); - final LinkedHashSet networkPrioritiesEqual = - new LinkedHashSet(); - networkPrioritiesEqual.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkPriority()); - networkPrioritiesEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); + final List networkTemplatesEqual = new ArrayList(); + networkTemplatesEqual.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); + networkTemplatesEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); final VcnGatewayConnectionConfig configEqual = - buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesEqual); + buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesEqual); - final LinkedHashSet networkPrioritiesNotEqual = - new LinkedHashSet(); - networkPrioritiesNotEqual.add( - VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkPriority()); + final List networkTemplatesNotEqual = new ArrayList(); + networkTemplatesNotEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); final VcnGatewayConnectionConfig configNotEqual = - buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesNotEqual); + buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesNotEqual); - assertEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesEqual); + assertEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesEqual); assertEquals(config, configEqual); - assertNotEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesNotEqual); + assertNotEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesNotEqual); assertNotEquals(config, configNotEqual); } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java index 652057fd48..cb5b47bbdc 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java @@ -15,36 +15,38 @@ */ package android.net.vcn; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; 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 org.junit.Test; +import java.util.Set; + public class VcnWifiUnderlyingNetworkTemplateTest { private static final String SSID = "TestWifi"; private static final int INVALID_NETWORK_QUALITY = -1; // Package private for use in VcnGatewayConnectionConfigTest - static VcnWifiUnderlyingNetworkTemplate getTestNetworkPriority() { + static VcnWifiUnderlyingNetworkTemplate getTestNetworkTemplate() { return new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setSsid(SSID) + .setMetered(MATCH_FORBIDDEN) + .setSsids(Set.of(SSID)) .build(); } @Test public void testBuilderAndGetters() { - final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); + final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); - assertTrue(networkPriority.allowMetered()); - assertEquals(SSID, networkPriority.getSsid()); + assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered()); + assertEquals(Set.of(SSID), networkPriority.getSsids()); } @Test @@ -52,8 +54,8 @@ public class VcnWifiUnderlyingNetworkTemplateTest { final VcnWifiUnderlyingNetworkTemplate networkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder().build(); assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); - assertFalse(networkPriority.allowMetered()); - assertNull(SSID, networkPriority.getSsid()); + assertEquals(MATCH_ANY, networkPriority.getMetered()); + assertTrue(networkPriority.getSsids().isEmpty()); } @Test @@ -68,7 +70,7 @@ public class VcnWifiUnderlyingNetworkTemplateTest { @Test public void testPersistableBundle() { - final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkPriority(); + final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); assertEquals( networkPriority, VcnUnderlyingNetworkTemplate.fromPersistableBundle( diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index f23d5bf67e..4bb7de8c1f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -16,6 +16,8 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.server.vcn.VcnTestUtils.setupSystemService; @@ -145,7 +147,7 @@ public class NetworkPriorityClassifierTest { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(false /* allowMetered */) + .setMetered(MATCH_FORBIDDEN) .build(); assertFalse( @@ -164,7 +166,6 @@ public class NetworkPriorityClassifierTest { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) .build(); final UnderlyingNetworkRecord selectedNetworkRecord = isSelectedNetwork ? mWifiNetworkRecord : null; @@ -214,8 +215,7 @@ public class NetworkPriorityClassifierTest { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setSsid(nwPrioritySsid) + .setSsids(Set.of(nwPrioritySsid)) .build(); assertEquals( @@ -238,10 +238,7 @@ public class NetworkPriorityClassifierTest { } private static VcnCellUnderlyingNetworkTemplate.Builder getCellNetworkPriorityBuilder() { - return new VcnCellUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) - .setAllowMetered(true /* allowMetered */) - .setAllowRoaming(true /* allowRoaming */); + return new VcnCellUnderlyingNetworkTemplate.Builder().setNetworkQuality(NETWORK_QUALITY_OK); } @Test @@ -258,9 +255,7 @@ public class NetworkPriorityClassifierTest { @Test public void testMatchOpportunisticCell() { final VcnCellUnderlyingNetworkTemplate opportunisticCellNetworkPriority = - getCellNetworkPriorityBuilder() - .setRequireOpportunistic(true /* requireOpportunistic */) - .build(); + getCellNetworkPriorityBuilder().setOpportunistic(MATCH_REQUIRED).build(); when(mSubscriptionSnapshot.isOpportunistic(SUB_ID)).thenReturn(true); when(mSubscriptionSnapshot.getAllSubIdsInGroup(SUB_GROUP)).thenReturn(new ArraySet<>()); @@ -279,7 +274,7 @@ public class NetworkPriorityClassifierTest { final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER; final VcnCellUnderlyingNetworkTemplate networkPriority = getCellNetworkPriorityBuilder() - .setAllowedOperatorPlmnIds(Set.of(networkPriorityPlmnId)) + .setOperatorPlmnIds(Set.of(networkPriorityPlmnId)) .build(); assertEquals( @@ -308,7 +303,7 @@ public class NetworkPriorityClassifierTest { final int networkPriorityCarrierId = useMatchedCarrierId ? CARRIER_ID : CARRIER_ID_OTHER; final VcnCellUnderlyingNetworkTemplate networkPriority = getCellNetworkPriorityBuilder() - .setAllowedSpecificCarrierIds(Set.of(networkPriorityCarrierId)) + .setSimSpecificCarrierIds(Set.of(networkPriorityCarrierId)) .build(); assertEquals( @@ -336,7 +331,7 @@ public class NetworkPriorityClassifierTest { @Test public void testMatchWifiFailWithoutNotRoamingBit() { final VcnCellUnderlyingNetworkTemplate networkPriority = - getCellNetworkPriorityBuilder().setAllowRoaming(false /* allowRoaming */).build(); + getCellNetworkPriorityBuilder().setRoaming(MATCH_FORBIDDEN).build(); assertFalse( checkMatchesCellPriorityRule( @@ -353,7 +348,7 @@ public class NetworkPriorityClassifierTest { calculatePriorityClass( mVcnContext, networkRecord, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, SUB_GROUP, mSubscriptionSnapshot, null /* currentlySelected */, From 3e75f6d4cc49649f38da3ddcbb93a6c9548da8d1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 14 Dec 2021 15:26:03 -0800 Subject: [PATCH 0297/1057] Expose APIs to configure underlying network priority This commit expose VcnUnderlyingNetworkTemplate classes and methods to configure those objects in VcnGatewayConnectionConfig. Those APIs allow callers to configure the underlying network priority for VCN gateway when VCN is doing route selection. Callers can construct VcnUnderlyingNeworkTemplate with network requirements and then set VcnUnderlyingNeworkTemplate list from most preffered to least preffered in VcnGatewayConnectionConfig. Bug: 205343355 CTS-Coverage-Bug: 209498272 Test: atest FrameworksVcnTests, CtsVcnTestCases Test: make update-api Change-Id: Ib7d51cf1ce562a1acbcb767ec569d7e11c861a1d --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 34 ++++++++++++------- .../net/vcn/VcnGatewayConnectionConfig.java | 20 +++++------ .../net/vcn/VcnUnderlyingNetworkTemplate.java | 22 ++++++------ .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 11 +++--- .../UnderlyingNetworkController.java | 6 ++-- .../vcn/VcnGatewayConnectionConfigTest.java | 10 +++--- 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 2dcb6872d6..125b5730b2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -49,8 +49,6 @@ import java.util.Set; * networks. * *

      See {@link VcnUnderlyingNetworkTemplate} - * - * @hide */ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds"; @@ -279,8 +277,13 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** * Set the matching criteria for metered networks. * + *

      A template where setMetered(MATCH_REQUIRED) will only match metered networks (one + * without NET_CAPABILITY_NOT_METERED). A template where setMetered(MATCH_FORBIDDEN) will + * only match a network that is not metered (one with NET_CAPABILITY_NOT_METERED). + * * @param matchCriteria the matching criteria for metered networks. Defaults to {@link - * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED */ // The matching getter is defined in the super class. Please see {@link // VcnUnderlyingNetworkTemplate#getMetered()} @@ -300,10 +303,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * priority from a partner's networks. * * @param operatorPlmnIds the matching operator PLMN IDs in String. Network with one of the - * matching PLMN IDs can match this template. Defaults to an empty set, allowing ANY - * PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 - * decimal digits. See {@link SubscriptionInfo#getMccString()} and {@link - * SubscriptionInfo#getMncString()}. + * matching PLMN IDs can match this template. If the set is empty, any PLMN ID will + * match. The default is an empty set. A valid PLMN is a concatenation of MNC and MCC, + * and thus consists of 5 or 6 decimal digits. + * @see SubscriptionInfo#getMccString() + * @see SubscriptionInfo#getMncString() */ @NonNull public Builder setOperatorPlmnIds(@NonNull Set operatorPlmnIds) { @@ -318,8 +322,9 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Set sim specific carrier IDs with which a network can match this template. * * @param simSpecificCarrierIds the matching sim specific carrier IDs. Network with one of - * the sim specific carrier IDs can match this template. Defaults to an empty set, - * allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}. + * the sim specific carrier IDs can match this template. If the set is empty, any + * carrier ID will match. The default is an empty set. + * @see TelephonyManager#getSimSpecificCarrierId() */ @NonNull public Builder setSimSpecificCarrierIds(@NonNull Set simSpecificCarrierIds) { @@ -333,8 +338,13 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** * Set the matching criteria for roaming networks. * + *

      A template where setRoaming(MATCH_REQUIRED) will only match roaming networks (one + * without NET_CAPABILITY_NOT_ROAMING). A template where setRoaming(MATCH_FORBIDDEN) will + * only match a network that is not roaming (one with NET_CAPABILITY_NOT_ROAMING). + * * @param matchCriteria the matching criteria for roaming networks. Defaults to {@link - * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}. + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING */ @NonNull public Builder setRoaming(@MatchCriteria int matchCriteria) { @@ -348,8 +358,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Set the matching criteria for opportunistic cellular subscriptions. * * @param matchCriteria the matching criteria for opportunistic cellular subscriptions. - * Defaults to {@link #MATCH_ANY}. See {@link - * SubscriptionManager#setOpportunistic(boolean, int)} + * Defaults to {@link #MATCH_ANY}. + * @see SubscriptionManager#setOpportunistic(boolean, int) */ @NonNull public Builder setOpportunistic(@MatchCriteria int matchCriteria) { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index f17f30a0d1..92956e859f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -375,11 +375,10 @@ public final class VcnGatewayConnectionConfig { /** * Retrieve the VcnUnderlyingNetworkTemplate list, or a default list if it is not configured. * - * @see Builder#setVcnUnderlyingNetworkTemplates(List) - * @hide + * @see Builder#setVcnUnderlyingNetworkPriorities(List) */ @NonNull - public List getVcnUnderlyingNetworkTemplates() { + public List getVcnUnderlyingNetworkPriorities() { return new ArrayList<>(mUnderlyingNetworkTemplates); } @@ -543,29 +542,28 @@ public final class VcnGatewayConnectionConfig { } /** - * Set the list of templates to match underlying networks against, in priority order. + * Set the list of templates to match underlying networks against, in high-to-low priority + * order. * - *

      To select the VCN underlying network, the VCN gateway will go through all the network - * candidates and return a network matching the highest priority rule. + *

      To select the VCN underlying network, the VCN connection will go through all the + * network candidates and return a network matching the highest priority rule. * *

      If multiple networks match the same rule, the VCN will prefer an already-selected * network as opposed to a new/unselected network. However, if both are new/unselected * networks, a network will be chosen arbitrarily amongst the networks matching the highest * priority rule. * - *

      A rule that matches all carrier-owned networks is implicitly added at the end of the - * priority list, ensuring that if all networks fail to match the rules provided, an - * underlying network will still be selected (at random if necessary). + *

      If all networks fail to match the rules provided, an underlying network will still be + * selected (at random if necessary). * * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are * ordered from most to least preferred, or an empty list to use the default * prioritization. The default network prioritization order is Opportunistic cellular, * Carrier WiFi and then Macro cellular. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull - public Builder setVcnUnderlyingNetworkTemplates( + public Builder setVcnUnderlyingNetworkPriorities( @NonNull List underlyingNetworkTemplates) { validateNetworkTemplateList(underlyingNetworkTemplates); diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 33b02e8f10..60fc936072 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -22,7 +22,6 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.NetworkCapabilities; import android.os.PersistableBundle; import android.util.SparseArray; @@ -41,9 +40,7 @@ import java.util.Objects; *

      Apps provisioning a VCN can configure the underlying network priority for each Gateway * Connection by setting a list (in priority order, most to least preferred) of the appropriate * subclasses in the VcnGatewayConnectionConfig. See {@link - * VcnGatewayConnectionConfig.Builder#setVcnUnderlyingNetworkTemplates} - * - * @hide + * VcnGatewayConnectionConfig.Builder#setVcnUnderlyingNetworkPriorities} */ public abstract class VcnUnderlyingNetworkTemplate { /** @hide */ @@ -69,22 +66,23 @@ public abstract class VcnUnderlyingNetworkTemplate { public @interface NetworkQuality {} /** - * Used to configure the matching criteria of a network capability (See {@link - * NetworkCapabilities}). Denotes that networks with or without the capability are both - * acceptable to match the template. + * Used to configure the matching criteria of a network characteristic. This may include network + * capabilities, or cellular subscription information. Denotes that networks with or without the + * characteristic are both acceptable to match this template. */ public static final int MATCH_ANY = 0; /** - * Used to configure the matching criteria of a network capability (See {@link - * NetworkCapabilities}). Denotes that only network with the capability can match the template. + * Used to configure the matching criteria of a network characteristic. This may include network + * capabilities, or cellular subscription information. Denotes that a network MUST have the + * capability in order to match this template. */ public static final int MATCH_REQUIRED = 1; /** - * Used to configure the matching criteria of a network capability (See {@link - * NetworkCapabilities}). Denotes that only network without the capability can match the - * template. + * Used to configure the matching criteria of a network characteristic. This may include network + * capabilities, or cellular subscription information. Denotes that a network MUST NOT have the + * capability in order to match this template. */ public static final int MATCH_FORBIDDEN = 2; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index fcf5b09430..272ca9dd75 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -40,8 +40,6 @@ import java.util.Set; * networks. * *

      See {@link VcnUnderlyingNetworkTemplate} - * - * @hide */ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { private static final String SSIDS_KEY = "mSsids"; @@ -168,8 +166,13 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** * Set the matching criteria for metered networks. * + *

      A template where setMetered(MATCH_REQUIRED) will only match metered networks (one + * without NET_CAPABILITY_NOT_METERED). A template where setMetered(MATCH_FORBIDDEN) will + * only match a network that is not metered (one with NET_CAPABILITY_NOT_METERED). + * * @param matchCriteria the matching criteria for metered networks. Defaults to {@link - * #MATCH_ANY}. See {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED */ // The matching getter is defined in the super class. Please see {@link // VcnUnderlyingNetworkTemplate#getMetered()} @@ -186,7 +189,7 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Set the SSIDs with which a network can match this priority rule. * * @param ssids the matching SSIDs. Network with one of the matching SSIDs can match this - * priority rule. Defaults to an empty set, allowing ANY SSID. + * priority rule. If the set is empty, any SSID will match. The default is an empty set. */ @NonNull public Builder setSsids(@NonNull Set ssids) { diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 6933e6641d..ca2e449ffc 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -401,7 +401,7 @@ public class UnderlyingNetworkController { new TreeSet<>( UnderlyingNetworkRecord.getComparator( mVcnContext, - mConnectionConfig.getVcnUnderlyingNetworkTemplates(), + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, @@ -502,7 +502,7 @@ public class UnderlyingNetworkController { pw.increaseIndent(); int index = 0; for (VcnUnderlyingNetworkTemplate priority : - mConnectionConfig.getVcnUnderlyingNetworkTemplates()) { + mConnectionConfig.getVcnUnderlyingNetworkPriorities()) { pw.println("Priority index: " + index); priority.dump(pw); index++; @@ -518,7 +518,7 @@ public class UnderlyingNetworkController { record.dump( mVcnContext, pw, - mConnectionConfig.getVcnUnderlyingNetworkTemplates(), + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index d7884e40b4..2aef9ae7ca 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -96,7 +96,7 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfig() { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setVcnUnderlyingNetworkTemplates(UNDERLYING_NETWORK_TEMPLATES); + newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES); return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS); } @@ -177,7 +177,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullNetworkTemplates() { try { - newBuilder().setVcnUnderlyingNetworkTemplates(null); + newBuilder().setVcnUnderlyingNetworkPriorities(null); fail("Expected exception due to invalid underlyingNetworkTemplates"); } catch (NullPointerException e) { } @@ -220,7 +220,7 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); - assertEquals(UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkTemplates()); + assertEquals(UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities()); assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); @@ -241,7 +241,7 @@ public class VcnGatewayConnectionConfigTest { final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle); assertEquals( - DEFAULT_UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkTemplates()); + DEFAULT_UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities()); } private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) { @@ -292,7 +292,7 @@ public class VcnGatewayConnectionConfigTest { new VcnGatewayConnectionConfig.Builder( "buildTestConfigWithVcnUnderlyingNetworkTemplates", TUNNEL_CONNECTION_PARAMS) - .setVcnUnderlyingNetworkTemplates(networkTemplates), + .setVcnUnderlyingNetworkPriorities(networkTemplates), EXPOSED_CAPS); } From 5f4a041442b2a21e15bb067aa805165c5dadc522 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 7 Jan 2022 21:05:21 +0000 Subject: [PATCH 0298/1057] Update TelephonySubscriptionTracker to use CarrierPrivilegesListener This change adds use for CarrierPrivilegesListener to use the callbacks as triggers to re-check carrier privileges. For simplicity, the carrier privileges returned by the callback are not used, as it requires an additional layer of caching. Instead, a query is performed, which should hit a cache in the CarrierPrivilegesTracker, thus not be performance-sensitive. Bug: 183554244 Test: atest FrameworksVcnTests Change-Id: Ia4529d087ee7f0deca7101c6849183ba7267c067 --- .../vcn/TelephonySubscriptionTracker.java | 103 ++++++++++++++++-- .../vcn/TelephonySubscriptionTrackerTest.java | 88 ++++++++++++++- 2 files changed, 179 insertions(+), 12 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index a31c56a3b7..a17e79273e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -38,15 +39,19 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -92,6 +97,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; + @NonNull + private final List mCarrierPrivilegesChangedListeners = + new ArrayList<>(); + @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; public TelephonySubscriptionTracker( @@ -126,22 +135,71 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { }; } - /** Registers the receivers, and starts tracking subscriptions. */ + /** + * Registers the receivers, and starts tracking subscriptions. + * + *

      Must always be run on the VcnManagementService thread. + */ public void register() { final HandlerExecutor executor = new HandlerExecutor(mHandler); + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); + filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED); - mContext.registerReceiver( - this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); + mContext.registerReceiver(this, filter, null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); + + registerCarrierPrivilegesListeners(); } - /** Unregisters the receivers, and stops tracking subscriptions. */ + private void registerCarrierPrivilegesListeners() { + final HandlerExecutor executor = new HandlerExecutor(mHandler); + final int modemCount = mTelephonyManager.getActiveModemCount(); + try { + for (int i = 0; i < modemCount; i++) { + CarrierPrivilegesListener carrierPrivilegesListener = + new CarrierPrivilegesListener() { + @Override + public void onCarrierPrivilegesChanged( + @NonNull List privilegedPackageNames, + @NonNull int[] privilegedUids) { + // Re-trigger the synchronous check (which is also very cheap due + // to caching in CarrierPrivilegesTracker). This allows consistency + // with the onSubscriptionsChangedListener and broadcasts. + handleSubscriptionsChanged(); + } + }; + + mTelephonyManager.addCarrierPrivilegesListener( + i, executor, carrierPrivilegesListener); + mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); + } + } catch (IllegalArgumentException e) { + Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e); + } + } + + /** + * Unregisters the receivers, and stops tracking subscriptions. + * + *

      Must always be run on the VcnManagementService thread. + */ public void unregister() { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); + + unregisterCarrierPrivilegesListeners(); + } + + private void unregisterCarrierPrivilegesListeners() { + for (CarrierPrivilegesListener carrierPrivilegesListener : + mCarrierPrivilegesChangedListeners) { + mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener); + } + mCarrierPrivilegesChangedListeners.clear(); } /** @@ -178,8 +236,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { // group. if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) { - // TODO (b/172619301): Cache based on callbacks from CarrierPrivilegesTracker - final TelephonyManager subIdSpecificTelephonyManager = mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); @@ -214,12 +270,39 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { */ @Override public void onReceive(Context context, Intent intent) { - // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it - // already was for an identified carrier, we can stop waiting for initial load to complete - if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { - return; + switch (intent.getAction()) { + case ACTION_CARRIER_CONFIG_CHANGED: + handleActionCarrierConfigChanged(context, intent); + break; + case ACTION_MULTI_SIM_CONFIG_CHANGED: + handleActionMultiSimConfigChanged(context, intent); + break; + default: + Slog.v(TAG, "Unknown intent received with action: " + intent.getAction()); + } + } + + private void handleActionMultiSimConfigChanged(Context context, Intent intent) { + unregisterCarrierPrivilegesListeners(); + + // Clear invalid slotIds from the mReadySubIdsBySlotId map. + final int modemCount = mTelephonyManager.getActiveModemCount(); + final Iterator slotIdIterator = mReadySubIdsBySlotId.keySet().iterator(); + while (slotIdIterator.hasNext()) { + final int slotId = slotIdIterator.next(); + + if (slotId >= modemCount) { + slotIdIterator.remove(); + } } + registerCarrierPrivilegesListeners(); + handleSubscriptionsChanged(); + } + + private void handleActionCarrierConfigChanged(Context context, Intent intent) { + // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it + // already was for an identified carrier, we can stop waiting for initial load to complete final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 1f0df62fe7..978bf3ed2e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -22,6 +22,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -34,8 +35,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -57,6 +60,8 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.CarrierPrivilegesListener; +import android.util.ArrayMap; import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -83,7 +88,7 @@ public class TelephonySubscriptionTrackerTest { private static final String PACKAGE_NAME = TelephonySubscriptionTrackerTest.class.getPackage().getName(); private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); - private static final int TEST_SIM_SLOT_INDEX = 1; + private static final int TEST_SIM_SLOT_INDEX = 0; private static final int TEST_SUBSCRIPTION_ID_1 = 2; private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); private static final int TEST_SUBSCRIPTION_ID_2 = 3; @@ -151,6 +156,8 @@ public class TelephonySubscriptionTrackerTest { @Before public void setUp() throws Exception { + doReturn(2).when(mTelephonyManager).getActiveModemCount(); + mCallback = mock(TelephonySubscriptionTrackerCallback.class); mTelephonySubscriptionTracker = new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); @@ -180,6 +187,15 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } + private List getCarrierPrivilegesListeners() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(CarrierPrivilegesListener.class); + verify(mTelephonyManager, atLeastOnce()) + .addCarrierPrivilegesListener(anyInt(), any(), captor.capture()); + + return captor.getAllValues(); + } + private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { final ArgumentCaptor captor = ArgumentCaptor.forClass(TelephonyCallback.class); @@ -188,6 +204,11 @@ public class TelephonySubscriptionTrackerTest { return (ActiveDataSubscriptionIdListener) captor.getValue(); } + private Intent buildTestMultiSimConfigBroadcastIntent() { + Intent intent = new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED); + return intent; + } + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); @@ -239,12 +260,21 @@ public class TelephonySubscriptionTrackerTest { any(), eq(mHandler)); final IntentFilter filter = getIntentFilter(); - assertEquals(1, filter.countActions()); + assertEquals(2, filter.countActions()); assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); + assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED)); verify(mSubscriptionManager) .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); assertNotNull(getOnSubscriptionsChangedListener()); + + verify(mTelephonyManager, times(2)) + .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + verify(mTelephonyManager) + .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + verify(mTelephonyManager) + .addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any()); + assertEquals(2, getCarrierPrivilegesListeners().size()); } @Test @@ -255,6 +285,49 @@ public class TelephonySubscriptionTrackerTest { final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener)); + + for (CarrierPrivilegesListener carrierPrivilegesListener : + getCarrierPrivilegesListeners()) { + verify(mTelephonyManager) + .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + } + } + + @Test + public void testMultiSimConfigChanged() throws Exception { + final ArrayMap readySubIdsBySlotId = new ArrayMap<>(); + readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1); + readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX + 1, TEST_SUBSCRIPTION_ID_1); + + mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId); + doReturn(1).when(mTelephonyManager).getActiveModemCount(); + + List carrierPrivilegesListeners = + getCarrierPrivilegesListeners(); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent()); + mTestLooper.dispatchAll(); + + for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) { + verify(mTelephonyManager) + .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + } + + // Expect cache cleared for inactive slots. + assertNull( + mTelephonySubscriptionTracker + .getReadySubIdsBySlotId() + .get(TEST_SIM_SLOT_INDEX + 1)); + + // Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other + // (2 previously registered during startup, for slots 0 & 1) + verify(mTelephonyManager, times(3)) + .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + verify(mTelephonyManager, times(2)) + .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + + // Verify that this triggers a re-evaluation + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } @Test @@ -313,6 +386,17 @@ public class TelephonySubscriptionTrackerTest { verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } + @Test + public void testOnCarrierPrivilegesChanged() throws Exception { + setupReadySubIds(); + + final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0); + listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {}); + mTestLooper.dispatchAll(); + + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); + } + @Test public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); From be995271b355ce81b9947068f0abb73ad2e2a5dc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 7 Jan 2022 21:56:04 +0000 Subject: [PATCH 0299/1057] Remove VCN Carrier Privilege grace period This change removes the grace period after the VCN is notified that a provisioning app is no longer carrier privileged. This is due to the switch to use CarrierPrivilegesTracker, which inherently has the identical grace period. This both simplifies the code, as well as removes some edge cases. As such, tests for the delay before VCN tears down are no longer necessary. Bug: 183554244 Test: atest FrameworksVcnTests Change-Id: Ia50223108e45eeaedc860adf5e29a6ea459d956f --- .../android/server/VcnManagementService.java | 58 +++------- .../server/VcnManagementServiceTest.java | 100 ++---------------- 2 files changed, 22 insertions(+), 136 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 0c990ecfc8..6a7afd90dc 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -24,7 +24,6 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; -import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -164,10 +163,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; - // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30); - /* Binder context for this service */ @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; @@ -372,12 +367,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - mNetworkProvider.register(); - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkCallback( - new NetworkRequest.Builder().clearCapabilities().build(), - mTrackingNetworkCallback); - mTelephonySubscriptionTracker.register(); + // Always run on the handler thread to ensure consistency. + mHandler.post(() -> { + mNetworkProvider.register(); + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mTrackingNetworkCallback); + mTelephonySubscriptionTracker.register(); + }); } private void enforcePrimaryUser() { @@ -471,22 +469,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!mVcns.containsKey(subGrp)) { startVcnLocked(subGrp, entry.getValue()); } - - // Cancel any scheduled teardowns for active subscriptions - mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } - // Schedule teardown of any VCN instances that have lost carrier privileges (after a - // delay) + // Schedule teardown of any VCN instances that have lost carrier privileges for (Entry entry : mVcns.entrySet()) { final ParcelUuid subGrp = entry.getKey(); final VcnConfig config = mConfigs.get(subGrp); final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); - final boolean isValidActiveDataSubIdNotInVcnSubGrp = - isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) - && !isActiveSubGroup(subGrp, snapshot); // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null @@ -496,31 +487,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); - // TODO(b/193687515): Support multiple VCNs active at the same time - // If directly switching to a subscription not in the current group, - // teardown immediately to prevent other subscription's network from being - // outscored by the VCN. Otherwise, teardown after a delay to ensure that - // SIM profile switches do not trigger the VCN to cycle. - final long teardownDelayMs = - isValidActiveDataSubIdNotInVcnSubGrp - ? 0 - : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; - mHandler.postDelayed(() -> { - synchronized (mLock) { - // Guard against case where this is run after a old instance was - // torn down, and a new instance was started. Verify to ensure - // correct instance is torn down. This could happen as a result of a - // Carrier App manually removing/adding a VcnConfig. - if (mVcns.get(uuidToTeardown) == instanceToTeardown) { - stopVcnLocked(uuidToTeardown); + stopVcnLocked(uuidToTeardown); - // TODO(b/181789060): invoke asynchronously after Vcn notifies - // through VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - uuidToTeardown, VCN_STATUS_CODE_INACTIVE); - } - } - }, instanceToTeardown, teardownDelayMs); + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 7c7dc4d79e..bb98bc0bab 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,7 +23,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -264,6 +263,7 @@ public class VcnManagementServiceTest { @Test public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); @@ -475,10 +475,8 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - - // Verify teardown after delay - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); verify(mMockPolicyListener).onPolicyChanged(); } @@ -504,92 +502,6 @@ public class VcnManagementServiceTest { assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); } - /** - * Tests an intermediate state where carrier privileges are marked as lost before active data - * subId changes during a SIM ejection. - * - *

      The expected outcome is that the VCN is torn down after a delay, as opposed to - * immediately. - */ - @Test - public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() - throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate privileges lost - triggerSubscriptionTrackerCbAndGetSnapshot( - TEST_SUBSCRIPTION_ID, - TEST_UUID_2, - Collections.emptySet(), - Collections.emptyMap(), - false /* hasCarrierPrivileges */); - - // Verify teardown after delay - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(vcn).teardownAsynchronously(); - } - - @Test - public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() - throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot( - INVALID_SUBSCRIPTION_ID, - null /* activeDataSubscriptionGroup */, - Collections.emptySet(), - Collections.emptyMap(), - false /* hasCarrierPrivileges */); - - // Simulate new SIM loaded right during teardown delay. - mTestLooper.moveTimeForward( - VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); - mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); - - // Verify that even after the full timeout duration, the VCN instance is not torn down - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(vcn, never()).teardownAsynchronously(); - } - - @Test - public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - - // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new - // vcnInstance. - mTestLooper.moveTimeForward( - VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); - mTestLooper.dispatchAll(); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); - triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); - final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); - - // Verify that new instance was different, and the old one was torn down - assertTrue(oldInstance != newInstance); - verify(oldInstance).teardownAsynchronously(); - - // Verify that even after the full timeout duration, the new VCN instance is not torn down - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(newInstance, never()).teardownAsynchronously(); - } - @Test public void testPackageChangeListenerRegistered() throws Exception { verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { @@ -925,6 +837,8 @@ public class VcnManagementServiceTest { private void setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); + triggerSubscriptionTrackerCbAndGetSnapshot( subGrp, Collections.singleton(subGrp), @@ -1020,6 +934,7 @@ public class VcnManagementServiceTest { private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); final ArgumentCaptor captor = ArgumentCaptor.forClass(NetworkCallback.class); @@ -1264,15 +1179,14 @@ public class VcnManagementServiceTest { true /* isActive */, true /* hasCarrierPrivileges */); - // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown - // timeout so the VCN goes inactive. + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes + // inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE From ab44f1155f87e0bd78ecb3ded6b9203ec9d6c0f7 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Wed, 12 Jan 2022 17:44:44 +0000 Subject: [PATCH 0300/1057] Revert "Migrate unsafe parcel APIs in framework-minus-apex" This reverts commit 8c5e8ca44ffbcec49d119b923fb552a1092617de. Reason for revert: b/214053959 Change-Id: Ic271bab1d3eaf677a5989dda9deb944ee2ad6850 --- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java | 2 +- .../src/android/net/vcn/VcnUnderlyingNetworkPolicy.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index fd3fe3731b..caab15251f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -173,7 +173,7 @@ public final class VcnConfig implements Parcelable { new Parcelable.Creator() { @NonNull public VcnConfig createFromParcel(Parcel in) { - return new VcnConfig((PersistableBundle) in.readParcelable(null, android.os.PersistableBundle.class)); + return new VcnConfig((PersistableBundle) in.readParcelable(null)); } @NonNull diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index fca084a00a..14e70cfeb1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -114,7 +114,7 @@ public final class VcnNetworkPolicyResult implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnNetworkPolicyResult createFromParcel(Parcel in) { - return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null, android.net.NetworkCapabilities.class)); + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); } public VcnNetworkPolicyResult[] newArray(int size) { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 5c47b28a7c..25a257423c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -146,7 +146,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); - final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class); + final WifiInfo wifiInfo = in.readParcelable(null); // If all fields are their null values, return null TransportInfo to avoid // leaking information about this being a VCN Network (instead of macro diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index 2b5305d05d..b0d4f3be24 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -106,7 +106,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy(in.readParcelable(null, android.net.vcn.VcnNetworkPolicyResult.class)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { From 006224d9f8f267fbee0f99f8c0903c9e45b9e780 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Jan 2022 00:08:23 +0000 Subject: [PATCH 0301/1057] Listen for individual subscription mobile data toggles This change ensures that the VCN listens for changes on a per-subscription basis. In the DSDS case, the Settings.Global.MOBILE_DATA toggles is insufficient, as the toggles for individual subscriptions are changed instead of the global toggle. Without this patch, the VCN may ignore changes in the user toggles, and continue providing data service even after user data is disabled. Similarly, it may fail to bring up a VCN when user data is re-enabled. Bug: 214247774 Test: atest FrameworksVcnTests Change-Id: I1e84c25f48eab90dca163eda809fc11d5d21bc31 --- .../src/com/android/server/vcn/Vcn.java | 69 ++++++++- .../java/com/android/server/vcn/VcnTest.java | 132 +++++++++++++++--- 2 files changed, 175 insertions(+), 26 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index e0cc8e1820..f29c40f743 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -39,10 +39,13 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -57,6 +60,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -148,6 +152,10 @@ public class Vcn extends Handler { @NonNull private final VcnContentResolver mContentResolver; @NonNull private final ContentObserver mMobileDataSettingsObserver; + @NonNull + private final Map mMobileDataStateListeners = + new ArrayMap<>(); + /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. * @@ -221,6 +229,9 @@ public class Vcn extends Handler { // Update mIsMobileDataEnabled before starting handling of NetworkRequests. mIsMobileDataEnabled = getMobileDataStatus(); + // Register mobile data state listeners. + updateMobileDataStateListeners(); + // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -348,6 +359,12 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } + // Unregister MobileDataStateListeners + for (VcnUserMobileDataStateListener listener : mMobileDataStateListeners.values()) { + getTelephonyManager().unregisterTelephonyCallback(listener); + } + mMobileDataStateListeners.clear(); + mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } @@ -454,11 +471,40 @@ public class Vcn extends Handler { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + updateMobileDataStateListeners(); + // Update the mobile data state after updating the subscription snapshot as a change in // subIds for a subGroup may affect the mobile data state. handleMobileDataToggled(); } + private void updateMobileDataStateListeners() { + final Set subIdsInGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); + final HandlerExecutor executor = new HandlerExecutor(this); + + // Register new callbacks + for (int subId : subIdsInGroup) { + if (!mMobileDataStateListeners.containsKey(subId)) { + final VcnUserMobileDataStateListener listener = + new VcnUserMobileDataStateListener(); + + getTelephonyManagerForSubid(subId).registerTelephonyCallback(executor, listener); + mMobileDataStateListeners.put(subId, listener); + } + } + + // Unregister old callbacks + Iterator> iterator = + mMobileDataStateListeners.entrySet().iterator(); + while (iterator.hasNext()) { + final Entry entry = iterator.next(); + if (!subIdsInGroup.contains(entry.getKey())) { + getTelephonyManager().unregisterTelephonyCallback(entry.getValue()); + iterator.remove(); + } + } + } + private void handleMobileDataToggled() { final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; mIsMobileDataEnabled = getMobileDataStatus(); @@ -493,11 +539,8 @@ public class Vcn extends Handler { } private boolean getMobileDataStatus() { - final TelephonyManager genericTelMan = - mVcnContext.getContext().getSystemService(TelephonyManager.class); - for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { + if (getTelephonyManagerForSubid(subId).isDataEnabled()) { return true; } } @@ -517,6 +560,14 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } + private TelephonyManager getTelephonyManager() { + return mVcnContext.getContext().getSystemService(TelephonyManager.class); + } + + private TelephonyManager getTelephonyManagerForSubid(int subid) { + return getTelephonyManager().createForSubscriptionId(subid); + } + private String getLogPrefix() { return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -670,6 +721,16 @@ public class Vcn extends Handler { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + class VcnUserMobileDataStateListener extends TelephonyCallback + implements TelephonyCallback.UserMobileDataStateListener { + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 5d2f9d7485..6d269686e4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -58,6 +58,7 @@ import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; @@ -207,6 +208,13 @@ public class VcnTest { .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); } + @Test + public void testMobileDataStateListenersRegistered() { + // Validate state from setUp() + verify(mTelephonyManager, times(3)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + } + @Test public void testMobileDataStateCheckedOnInitialization_enabled() { // Validate state from setUp() @@ -263,6 +271,24 @@ public class VcnTest { assertFalse(mVcn.isMobileDataEnabled()); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataStateListeners() { + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + + doReturn(new ArraySet<>(Arrays.asList(2, 4))) + .when(updatedSnapshot) + .getAllSubIdsInGroup(any()); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + verify(mTelephonyManager, times(4)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + verify(mTelephonyManager, times(2)) + .unregisterTelephonyCallback(any(VcnUserMobileDataStateListener.class)); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -402,24 +428,17 @@ public class VcnTest { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } - private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { - final ArgumentCaptor captor = - ArgumentCaptor.forClass(ContentObserver.class); - verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); - final ContentObserver contentObserver = captor.getValue(); - + private void setupForMobileDataTest(boolean startingToggleState) { // Start VcnGatewayConnections final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); triggerVcnRequestListeners(requestListener); - final Map gateways = - mVcn.getVcnGatewayConnectionConfigMap(); - - // Trigger data toggle change. - doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); - contentObserver.onChange(false /* selfChange, ignored */); - mTestLooper.dispatchAll(); + } + private void verifyMobileDataToggledUpdatesGatewayConnections( + boolean startingToggleState, + boolean endingToggleState, + Map gateways) { // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the // toggle state changed. for (Entry entry : gateways.entrySet()) { @@ -433,29 +452,98 @@ public class VcnTest { } } + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); if (startingToggleState != endingToggleState) { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } - @Test - public void testMobileDataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); + private void verifyGlobalMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); } @Test - public void testMobileDataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + public void testGlobalMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testGlobalMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + } + + private void verifySubscriptionMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + final ArgumentCaptor captor = + ArgumentCaptor.forClass(VcnUserMobileDataStateListener.class); + verify(mTelephonyManager, times(3)).registerTelephonyCallback(any(), captor.capture()); + final VcnUserMobileDataStateListener listener = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + listener.onUserMobileDataStateChanged(false /* enabled, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); + } + + @Test + public void testSubscriptionMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); } } From cbed7917ceb728f6c537ed1085ac77db6aa507cd Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Wed, 12 Jan 2022 17:44:44 +0000 Subject: [PATCH 0302/1057] Revert "Migrate unsafe parcel APIs in framework-minus-apex" This reverts commit 8c5e8ca44ffbcec49d119b923fb552a1092617de. Reason for revert: b/214053959 Change-Id: Ic271bab1d3eaf677a5989dda9deb944ee2ad6850 (cherry picked from commit ab44f1155f87e0bd78ecb3ded6b9203ec9d6c0f7) Merged-In:Ic271bab1d3eaf677a5989dda9deb944ee2ad6850 --- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java | 2 +- .../src/android/net/vcn/VcnUnderlyingNetworkPolicy.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index fd3fe3731b..caab15251f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -173,7 +173,7 @@ public final class VcnConfig implements Parcelable { new Parcelable.Creator() { @NonNull public VcnConfig createFromParcel(Parcel in) { - return new VcnConfig((PersistableBundle) in.readParcelable(null, android.os.PersistableBundle.class)); + return new VcnConfig((PersistableBundle) in.readParcelable(null)); } @NonNull diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index fca084a00a..14e70cfeb1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -114,7 +114,7 @@ public final class VcnNetworkPolicyResult implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnNetworkPolicyResult createFromParcel(Parcel in) { - return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null, android.net.NetworkCapabilities.class)); + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); } public VcnNetworkPolicyResult[] newArray(int size) { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 5c47b28a7c..25a257423c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -146,7 +146,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); - final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class); + final WifiInfo wifiInfo = in.readParcelable(null); // If all fields are their null values, return null TransportInfo to avoid // leaking information about this being a VCN Network (instead of macro diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index 2b5305d05d..b0d4f3be24 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -106,7 +106,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy(in.readParcelable(null, android.net.vcn.VcnNetworkPolicyResult.class)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { From 432b1982fff3f95f7c69a68c68d99e24e5c04ddd Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 16 Dec 2021 19:34:03 +0000 Subject: [PATCH 0303/1057] Add minimum required bandwidth to network templates This change adds a minimum required bandwidth to the VCN network templates, ensuring that a minimum bar of throughput can be required of underlying networks. Bug: 211008106 Test: atest FrameworksVcnTests Change-Id: I929428f75e5e543966a03061d13f300dd8b0956f --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 149 +++++++++++++--- .../net/vcn/VcnGatewayConnectionConfig.java | 4 - .../net/vcn/VcnUnderlyingNetworkTemplate.java | 167 ++++++++++++------ .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 156 +++++++++++++--- .../NetworkPriorityClassifier.java | 36 ++-- .../VcnCellUnderlyingNetworkTemplateTest.java | 56 +++++- .../VcnUnderlyingNetworkTemplateTestBase.java | 24 +++ .../VcnWifiUnderlyingNetworkTemplateTest.java | 54 ++++-- .../NetworkPriorityClassifierTest.java | 155 +++++++++++++++- 9 files changed, 660 insertions(+), 141 deletions(-) create mode 100644 Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 125b5730b2..44fe94ca18 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -63,13 +63,22 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork private final int mOpportunisticMatchCriteria; private VcnCellUnderlyingNetworkTemplate( - int networkQuality, int meteredMatchCriteria, + int minEntryUpstreamBandwidthKbps, + int minExitUpstreamBandwidthKbps, + int minEntryDownstreamBandwidthKbps, + int minExitDownstreamBandwidthKbps, Set allowedNetworkPlmnIds, Set allowedSpecificCarrierIds, int roamingMatchCriteria, int opportunisticMatchCriteria) { - super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, meteredMatchCriteria); + super( + NETWORK_PRIORITY_TYPE_CELL, + meteredMatchCriteria, + minEntryUpstreamBandwidthKbps, + minExitUpstreamBandwidthKbps, + minEntryDownstreamBandwidthKbps, + minExitDownstreamBandwidthKbps); mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds); mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds); mRoamingMatchCriteria = roamingMatchCriteria; @@ -109,9 +118,17 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle is null"); - final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY); + final int minEntryUpstreamBandwidthKbps = + in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minExitUpstreamBandwidthKbps = + in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minEntryDownstreamBandwidthKbps = + in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minExitDownstreamBandwidthKbps = + in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final PersistableBundle plmnIdsBundle = in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY); Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null"); @@ -131,8 +148,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork final int opportunisticMatchCriteria = in.getInt(OPPORTUNISTIC_MATCH_KEY); return new VcnCellUnderlyingNetworkTemplate( - networkQuality, meteredMatchCriteria, + minEntryUpstreamBandwidthKbps, + minExitUpstreamBandwidthKbps, + minEntryDownstreamBandwidthKbps, + minExitDownstreamBandwidthKbps, allowedNetworkPlmnIds, allowedSpecificCarrierIds, roamingMatchCriteria, @@ -243,7 +263,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** This class is used to incrementally build VcnCellUnderlyingNetworkTemplate objects. */ public static final class Builder { - private int mNetworkQuality = NETWORK_QUALITY_ANY; private int mMeteredMatchCriteria = MATCH_ANY; @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); @@ -252,28 +271,14 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork private int mRoamingMatchCriteria = MATCH_ANY; private int mOpportunisticMatchCriteria = MATCH_ANY; + private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + /** Construct a Builder object. */ public Builder() {} - /** - * Set the required network quality to match this template. - * - *

      Network quality is a aggregation of multiple signals that reflect the network link - * metrics. For example, the network validation bit (see {@link - * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth - * and signal strength. - * - * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY - * @hide - */ - @NonNull - public Builder setNetworkQuality(@NetworkQuality int networkQuality) { - validateNetworkQuality(networkQuality); - - mNetworkQuality = networkQuality; - return this; - } - /** * Set the matching criteria for metered networks. * @@ -369,12 +374,106 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return this; } + /** + * Set the minimum accepted entry and exit upstream bandwidth allowed by this template. + * + *

      The minimum upstream bandwidth condition allows for separate entry and exit + * thresholds, allowing for a margin of confidence before matching a network, while + * requiring a minimum bandwidth to continue being matching. In order to match this + * template, a network must fulfill one of the following two cases, depending on whether the + * network being evaluated is the Gateway Connection's underlying network: + * + *

        + *
      • Network IS selected, AND the Network's estimated upstream bandwidth is greater than + * or equal to the minExitUpstreamBandwidthKbps provided. + *
      • Network IS NOT selected, AND the Network's estimated upstream bandwidth is greater + * than or equal to the minEntryUpstreamBandwidthKbps provided. + *
      + * + *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be + * unable to meet the conditions for staying selected (exit criteria), the entry criteria + * MUST be greater than, or equal to the exit criteria. + * + *

      Estimated bandwidth of a network is provided by the transport layer, and reported in + * {@link NetworkCapabilities}. The provided estimates will be used without modification. + * + * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a + * network that IS NOT an already-selected underlying network, or {@code 0} to disable + * this requirement. MUST be greater than, or equal to minExitUpstreamBandwidthKbps. + * Defaults to {@code 0} + * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network + * that IS the already-selected underlying network, or {@code 0} to disable this + * requirement. MUST be less than, or equal to minEntryUpstreamBandwidthKbps. Defaults + * to {@code 0} + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setMinUpstreamBandwidthKbps( + int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) { + validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps); + + mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps; + mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps; + + return this; + } + + /** + * Set the minimum acceptable downstream bandwidths allowed by this template. + * + *

      The minimum downstream bandwidth condition allows for separate entry and exit + * thresholds, allowing for a margin of confidence before matching a network, while + * requiring a minimum bandwidth to continue being matching. In order to match this + * template, a network must fulfill one of the following two cases, depending on whether the + * network being evaluated is the Gateway Connection's underlying network: + * + *

        + *
      • Network IS selected, AND the Network's estimated downstream bandwidth is greater + * than or equal to the minExitDownstreamBandwidthKbps provided. + *
      • Network IS NOT selected, AND the Network's estimated downstream bandwidth is + * greater than or equal to the minEntryDownstreamBandwidthKbps provided. + *
      + * + *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be + * unable to meet the conditions for staying selected (exit criteria), the entry criteria + * MUST be greater than, or equal to the exit criteria. + * + *

      Estimated bandwidth of a network is provided by the transport layer, and reported in + * {@link NetworkCapabilities}. The provided estimates will be used without modification. + * + * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a + * network that IS NOT an already-selected underlying network, or {@code 0} to disable + * this requirement. MUST be greater than, or equal to minExitDownstreamBandwidthKbps. + * Defaults to {@code 0} + * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a + * network that IS the already-selected underlying network, or {@code 0} to disable this + * requirement. MUST be less than, or equal to minEntryDownstreamBandwidthKbps. Defaults + * to {@code 0} + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setMinDownstreamBandwidthKbps( + int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) { + validateMinBandwidthKbps( + minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps); + + mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps; + mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps; + + return this; + } + /** Build the VcnCellUnderlyingNetworkTemplate. */ @NonNull public VcnCellUnderlyingNetworkTemplate build() { return new VcnCellUnderlyingNetworkTemplate( - mNetworkQuality, mMeteredMatchCriteria, + mMinEntryUpstreamBandwidthKbps, + mMinExitUpstreamBandwidthKbps, + mMinEntryDownstreamBandwidthKbps, + mMinExitDownstreamBandwidthKbps, mAllowedNetworkPlmnIds, mAllowedSpecificCarrierIds, mRoamingMatchCriteria, diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 92956e859f..a6830b708c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -17,7 +17,6 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.internal.annotations.VisibleForTesting.Visibility; @@ -169,18 +168,15 @@ public final class VcnGatewayConnectionConfig { static { DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .setOpportunistic(MATCH_REQUIRED) .build()); DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .build()); DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add( new VcnCellUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .build()); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 60fc936072..c39b24f1fc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -48,23 +48,6 @@ public abstract class VcnUnderlyingNetworkTemplate { /** @hide */ static final int NETWORK_PRIORITY_TYPE_CELL = 2; - /** Denotes that any network quality is acceptable. @hide */ - public static final int NETWORK_QUALITY_ANY = 0; - /** Denotes that network quality needs to be OK. @hide */ - public static final int NETWORK_QUALITY_OK = 100000; - - private static final SparseArray NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>(); - - static { - NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_ANY, "NETWORK_QUALITY_ANY"); - NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_OK, "NETWORK_QUALITY_OK"); - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY}) - public @interface NetworkQuality {} - /** * Used to configure the matching criteria of a network characteristic. This may include network * capabilities, or cellular subscription information. Denotes that networks with or without the @@ -102,45 +85,74 @@ public abstract class VcnUnderlyingNetworkTemplate { private static final String NETWORK_PRIORITY_TYPE_KEY = "mNetworkPriorityType"; private final int mNetworkPriorityType; - /** @hide */ - static final String NETWORK_QUALITY_KEY = "mNetworkQuality"; - - private final int mNetworkQuality; - /** @hide */ static final String METERED_MATCH_KEY = "mMeteredMatchCriteria"; private final int mMeteredMatchCriteria; + /** @hide */ + public static final int DEFAULT_MIN_BANDWIDTH_KBPS = 0; + + /** @hide */ + static final String MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY = "mMinEntryUpstreamBandwidthKbps"; + + private final int mMinEntryUpstreamBandwidthKbps; + + /** @hide */ + static final String MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY = "mMinExitUpstreamBandwidthKbps"; + + private final int mMinExitUpstreamBandwidthKbps; + + /** @hide */ + static final String MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY = + "mMinEntryDownstreamBandwidthKbps"; + + private final int mMinEntryDownstreamBandwidthKbps; + + /** @hide */ + static final String MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY = "mMinExitDownstreamBandwidthKbps"; + + private final int mMinExitDownstreamBandwidthKbps; + /** @hide */ VcnUnderlyingNetworkTemplate( - int networkPriorityType, int networkQuality, int meteredMatchCriteria) { + int networkPriorityType, + int meteredMatchCriteria, + int minEntryUpstreamBandwidthKbps, + int minExitUpstreamBandwidthKbps, + int minEntryDownstreamBandwidthKbps, + int minExitDownstreamBandwidthKbps) { mNetworkPriorityType = networkPriorityType; - mNetworkQuality = networkQuality; mMeteredMatchCriteria = meteredMatchCriteria; + mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps; + mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps; + mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps; + mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps; } /** @hide */ - static void validateNetworkQuality(int networkQuality) { + static void validateMatchCriteria(int matchCriteria, String matchingCapability) { Preconditions.checkArgument( - networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK, - "Invalid networkQuality:" + networkQuality); + MATCH_CRITERIA_TO_STRING_MAP.contains(matchCriteria), + "Invalid matching criteria: " + matchCriteria + " for " + matchingCapability); } /** @hide */ - static void validateMatchCriteria(int meteredMatchCriteria, String matchingCapability) { + static void validateMinBandwidthKbps(int minEntryBandwidth, int minExitBandwidth) { Preconditions.checkArgument( - MATCH_CRITERIA_TO_STRING_MAP.contains(meteredMatchCriteria), - "Invalid matching criteria: " - + meteredMatchCriteria - + " for " - + matchingCapability); + minEntryBandwidth >= 0, "Invalid minEntryBandwidth, must be >= 0"); + Preconditions.checkArgument( + minExitBandwidth >= 0, "Invalid minExitBandwidth, must be >= 0"); + Preconditions.checkArgument( + minEntryBandwidth >= minExitBandwidth, + "Minimum entry bandwidth must be >= exit bandwidth"); } /** @hide */ protected void validate() { - validateNetworkQuality(mNetworkQuality); validateMatchCriteria(mMeteredMatchCriteria, "mMeteredMatchCriteria"); + validateMinBandwidthKbps(mMinEntryUpstreamBandwidthKbps, mMinExitUpstreamBandwidthKbps); + validateMinBandwidthKbps(mMinEntryDownstreamBandwidthKbps, mMinExitDownstreamBandwidthKbps); } /** @hide */ @@ -168,15 +180,24 @@ public abstract class VcnUnderlyingNetworkTemplate { final PersistableBundle result = new PersistableBundle(); result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType); - result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality); result.putInt(METERED_MATCH_KEY, mMeteredMatchCriteria); + result.putInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, mMinEntryUpstreamBandwidthKbps); + result.putInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, mMinExitUpstreamBandwidthKbps); + result.putInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, mMinEntryDownstreamBandwidthKbps); + result.putInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, mMinExitDownstreamBandwidthKbps); return result; } @Override public int hashCode() { - return Objects.hash(mNetworkPriorityType, mNetworkQuality, mMeteredMatchCriteria); + return Objects.hash( + mNetworkPriorityType, + mMeteredMatchCriteria, + mMinEntryUpstreamBandwidthKbps, + mMinExitUpstreamBandwidthKbps, + mMinEntryDownstreamBandwidthKbps, + mMinExitDownstreamBandwidthKbps); } @Override @@ -187,8 +208,11 @@ public abstract class VcnUnderlyingNetworkTemplate { final VcnUnderlyingNetworkTemplate rhs = (VcnUnderlyingNetworkTemplate) other; return mNetworkPriorityType == rhs.mNetworkPriorityType - && mNetworkQuality == rhs.mNetworkQuality - && mMeteredMatchCriteria == rhs.mMeteredMatchCriteria; + && mMeteredMatchCriteria == rhs.mMeteredMatchCriteria + && mMinEntryUpstreamBandwidthKbps == rhs.mMinEntryUpstreamBandwidthKbps + && mMinExitUpstreamBandwidthKbps == rhs.mMinExitUpstreamBandwidthKbps + && mMinEntryDownstreamBandwidthKbps == rhs.mMinEntryDownstreamBandwidthKbps + && mMinExitDownstreamBandwidthKbps == rhs.mMinExitDownstreamBandwidthKbps; } /** @hide */ @@ -197,8 +221,8 @@ public abstract class VcnUnderlyingNetworkTemplate { } /** @hide */ - static String getMatchCriteriaString(int meteredMatchCriteria) { - return getNameString(MATCH_CRITERIA_TO_STRING_MAP, meteredMatchCriteria); + static String getMatchCriteriaString(int matchCriteria) { + return getNameString(MATCH_CRITERIA_TO_STRING_MAP, matchCriteria); } /** @hide */ @@ -213,34 +237,67 @@ public abstract class VcnUnderlyingNetworkTemplate { pw.println(this.getClass().getSimpleName() + ":"); pw.increaseIndent(); - pw.println( - "mNetworkQuality: " - + getNameString(NETWORK_QUALITY_TO_STRING_MAP, mNetworkQuality)); pw.println("mMeteredMatchCriteria: " + getMatchCriteriaString(mMeteredMatchCriteria)); + pw.println("mMinEntryUpstreamBandwidthKbps: " + mMinEntryUpstreamBandwidthKbps); + pw.println("mMinExitUpstreamBandwidthKbps: " + mMinExitUpstreamBandwidthKbps); + pw.println("mMinEntryDownstreamBandwidthKbps: " + mMinEntryDownstreamBandwidthKbps); + pw.println("mMinExitDownstreamBandwidthKbps: " + mMinExitDownstreamBandwidthKbps); dumpTransportSpecificFields(pw); pw.decreaseIndent(); } - /** - * Retrieve the required network quality to match this template. - * - * @see Builder#setNetworkQuality(int) - * @hide - */ - @NetworkQuality - public int getNetworkQuality() { - return mNetworkQuality; - } - /** * Return the matching criteria for metered networks. * * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMetered(int) * @see VcnCellUnderlyingNetworkTemplate.Builder#setMetered(int) */ - @MatchCriteria public int getMetered() { return mMeteredMatchCriteria; } + + /** + * Returns the minimum entry upstream bandwidth allowed by this template. + * + * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) + * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) + * @hide + */ + public int getMinEntryUpstreamBandwidthKbps() { + return mMinEntryUpstreamBandwidthKbps; + } + + /** + * Returns the minimum exit upstream bandwidth allowed by this template. + * + * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) + * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) + * @hide + */ + public int getMinExitUpstreamBandwidthKbps() { + return mMinExitUpstreamBandwidthKbps; + } + + /** + * Returns the minimum entry downstream bandwidth allowed by this template. + * + * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) + * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) + * @hide + */ + public int getMinEntryDownstreamBandwidthKbps() { + return mMinEntryDownstreamBandwidthKbps; + } + + /** + * Returns the minimum exit downstream bandwidth allowed by this template. + * + * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) + * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) + * @hide + */ + public int getMinExitDownstreamBandwidthKbps() { + return mMinExitDownstreamBandwidthKbps; + } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 272ca9dd75..43ae8b2d92 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -46,8 +46,19 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @Nullable private final Set mSsids; private VcnWifiUnderlyingNetworkTemplate( - int networkQuality, int meteredMatchCriteria, Set ssids) { - super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, meteredMatchCriteria); + int meteredMatchCriteria, + int minEntryUpstreamBandwidthKbps, + int minExitUpstreamBandwidthKbps, + int minEntryDownstreamBandwidthKbps, + int minExitDownstreamBandwidthKbps, + Set ssids) { + super( + NETWORK_PRIORITY_TYPE_WIFI, + meteredMatchCriteria, + minEntryUpstreamBandwidthKbps, + minExitUpstreamBandwidthKbps, + minEntryDownstreamBandwidthKbps, + minExitDownstreamBandwidthKbps); mSsids = new ArraySet<>(ssids); validate(); @@ -75,15 +86,29 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle is null"); - final int networkQuality = in.getInt(NETWORK_QUALITY_KEY); final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY); + final int minEntryUpstreamBandwidthKbps = + in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minExitUpstreamBandwidthKbps = + in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minEntryDownstreamBandwidthKbps = + in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final int minExitDownstreamBandwidthKbps = + in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); + final PersistableBundle ssidsBundle = in.getPersistableBundle(SSIDS_KEY); Objects.requireNonNull(ssidsBundle, "ssidsBundle is null"); final Set ssids = new ArraySet( PersistableBundleUtils.toList(ssidsBundle, STRING_DESERIALIZER)); - return new VcnWifiUnderlyingNetworkTemplate(networkQuality, meteredMatchCriteria, ssids); + return new VcnWifiUnderlyingNetworkTemplate( + meteredMatchCriteria, + minEntryUpstreamBandwidthKbps, + minExitUpstreamBandwidthKbps, + minEntryDownstreamBandwidthKbps, + minExitDownstreamBandwidthKbps, + ssids); } /** @hide */ @@ -137,32 +162,17 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ public static final class Builder { - private int mNetworkQuality = NETWORK_QUALITY_ANY; private int mMeteredMatchCriteria = MATCH_ANY; @NonNull private final Set mSsids = new ArraySet<>(); + private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; + /** Construct a Builder object. */ public Builder() {} - /** - * Set the required network quality to match this template. - * - *

      Network quality is a aggregation of multiple signals that reflect the network link - * metrics. For example, the network validation bit (see {@link - * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth - * and signal strength. - * - * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY - * @hide - */ - @NonNull - public Builder setNetworkQuality(@NetworkQuality int networkQuality) { - validateNetworkQuality(networkQuality); - - mNetworkQuality = networkQuality; - return this; - } - /** * Set the matching criteria for metered networks. * @@ -200,11 +210,107 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return this; } + /** + * Set the minimum accepted entry and exit upstream bandwidth allowed by this template. + * + *

      The minimum upstream bandwidth condition allows for separate entry and exit + * thresholds, allowing for a margin of confidence before matching a network, while + * requiring a minimum bandwidth to continue being matching. In order to match this + * template, a network must fulfill one of the following two cases, depending on whether the + * network being evaluated is the Gateway Connection's underlying network: + * + *

        + *
      • Network IS selected, AND the Network's estimated upstream bandwidth is greater than + * or equal to the minExitUpstreamBandwidthKbps provided. + *
      • Network IS NOT selected, AND the Network's estimated upstream bandwidth is greater + * than or equal to the minEntryUpstreamBandwidthKbps provided. + *
      + * + *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be + * unable to meet the conditions for staying selected (exit criteria), the entry criteria + * MUST be greater than, or equal to the exit criteria. + * + *

      Estimated bandwidth of a network is provided by the transport layer, and reported in + * {@link NetworkCapabilities}. The provided estimates will be used without modification. + * + * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a + * network that IS NOT an already-selected underlying network, or {@code 0} to disable + * this requirement. MUST be greater than, or equal to minExitUpstreamBandwidthKbps. + * Defaults to {@code 0} + * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network + * that IS the already-selected underlying network, or {@code 0} to disable this + * requirement. MUST be less than, or equal to minEntryUpstreamBandwidthKbps. Defaults + * to {@code 0} + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setMinUpstreamBandwidthKbps( + int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) { + validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps); + + mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps; + mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps; + + return this; + } + + /** + * Set the minimum acceptable downstream bandwidths allowed by this template. + * + *

      The minimum downstream bandwidth condition allows for separate entry and exit + * thresholds, allowing for a margin of confidence before matching a network, while + * requiring a minimum bandwidth to continue being matching. In order to match this + * template, a network must fulfill one of the following two cases, depending on whether the + * network being evaluated is the Gateway Connection's underlying network: + * + *

        + *
      • Network IS selected, AND the Network's estimated downstream bandwidth is greater + * than or equal to the minExitDownstreamBandwidthKbps provided. + *
      • Network IS NOT selected, AND the Network's estimated downstream bandwidth is + * greater than or equal to the minEntryDownstreamBandwidthKbps provided. + *
      + * + *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be + * unable to meet the conditions for staying selected (exit criteria), the entry criteria + * MUST be greater than, or equal to the exit criteria. + * + *

      Estimated bandwidth of a network is provided by the transport layer, and reported in + * {@link NetworkCapabilities}. The provided estimates will be used without modification. + * + * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a + * network that IS NOT an already-selected underlying network, or {@code 0} to disable + * this requirement. MUST be greater than, or equal to minExitDownstreamBandwidthKbps. + * Defaults to {@code 0} + * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a + * network that IS the already-selected underlying network, or {@code 0} to disable this + * requirement. MUST be less than, or equal to minEntryDownstreamBandwidthKbps. Defaults + * to {@code 0} + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setMinDownstreamBandwidthKbps( + int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) { + validateMinBandwidthKbps( + minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps); + + mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps; + mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps; + + return this; + } + /** Build the VcnWifiUnderlyingNetworkTemplate. */ @NonNull public VcnWifiUnderlyingNetworkTemplate build() { return new VcnWifiUnderlyingNetworkTemplate( - mNetworkQuality, mMeteredMatchCriteria, mSsids); + mMeteredMatchCriteria, + mMinEntryUpstreamBandwidthKbps, + mMinExitUpstreamBandwidthKbps, + mMinEntryDownstreamBandwidthKbps, + mMinExitDownstreamBandwidthKbps, + mSsids); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 6db25b7ed5..c96c1ee01a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -22,8 +22,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static com.android.server.VcnManagementService.LOCAL_LOG; @@ -47,6 +45,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.VcnContext; import java.util.List; +import java.util.Objects; import java.util.Set; /** @hide */ @@ -121,9 +120,10 @@ class NetworkPriorityClassifier { TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundle carrierConfig) { - // TODO: Check Network Quality reported by metric monitors/probers. - final NetworkCapabilities caps = networkRecord.networkCapabilities; + final boolean isSelectedUnderlyingNetwork = + currentlySelected != null + && Objects.equals(currentlySelected.network, networkRecord.network); final int meteredMatch = networkPriority.getMetered(); final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED); @@ -132,6 +132,23 @@ class NetworkPriorityClassifier { return false; } + // Fails bandwidth requirements if either (a) less than exit threshold, or (b), not + // selected, but less than entry threshold + if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps() + || (caps.getLinkUpstreamBandwidthKbps() + < networkPriority.getMinEntryUpstreamBandwidthKbps() + && !isSelectedUnderlyingNetwork)) { + return false; + } + + if (caps.getLinkDownstreamBandwidthKbps() + < networkPriority.getMinExitDownstreamBandwidthKbps() + || (caps.getLinkDownstreamBandwidthKbps() + < networkPriority.getMinEntryDownstreamBandwidthKbps() + && !isSelectedUnderlyingNetwork)) { + return false; + } + if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { return true; } @@ -172,8 +189,7 @@ class NetworkPriorityClassifier { } // TODO: Move the Network Quality check to the network metric monitor framework. - if (networkPriority.getNetworkQuality() - > getWifiQuality(networkRecord, currentlySelected, carrierConfig)) { + if (!isWifiRssiAcceptable(networkRecord, currentlySelected, carrierConfig)) { return false; } @@ -185,7 +201,7 @@ class NetworkPriorityClassifier { return true; } - private static int getWifiQuality( + private static boolean isWifiRssiAcceptable( UnderlyingNetworkRecord networkRecord, UnderlyingNetworkRecord currentlySelected, PersistableBundle carrierConfig) { @@ -196,14 +212,14 @@ class NetworkPriorityClassifier { if (isSelectedNetwork && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { - return NETWORK_QUALITY_OK; + return true; } if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { - return NETWORK_QUALITY_OK; + return true; } - return NETWORK_QUALITY_ANY; + return false; } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index 4a724b72f5..2fbcf9d87b 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -18,25 +18,29 @@ package android.net.vcn; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import org.junit.Test; import java.util.HashSet; import java.util.Set; -public class VcnCellUnderlyingNetworkTemplateTest { +public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); // Package private for use in VcnGatewayConnectionConfigTest static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { return new VcnCellUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .setMetered(MATCH_FORBIDDEN) + .setMinUpstreamBandwidthKbps( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS) + .setMinDownstreamBandwidthKbps( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .setOperatorPlmnIds(ALLOWED_PLMN_IDS) .setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS) .setRoaming(MATCH_FORBIDDEN) @@ -47,8 +51,19 @@ public class VcnCellUnderlyingNetworkTemplateTest { @Test public void testBuilderAndGetters() { final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); - assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered()); + assertEquals( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinEntryUpstreamBandwidthKbps()); + assertEquals( + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinExitUpstreamBandwidthKbps()); + assertEquals( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinEntryDownstreamBandwidthKbps()); + assertEquals( + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinExitDownstreamBandwidthKbps()); assertEquals(ALLOWED_PLMN_IDS, networkPriority.getOperatorPlmnIds()); assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getSimSpecificCarrierIds()); assertEquals(MATCH_FORBIDDEN, networkPriority.getRoaming()); @@ -59,14 +74,43 @@ public class VcnCellUnderlyingNetworkTemplateTest { public void testBuilderAndGettersForDefaultValues() { final VcnCellUnderlyingNetworkTemplate networkPriority = new VcnCellUnderlyingNetworkTemplate.Builder().build(); - assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); assertEquals(MATCH_ANY, networkPriority.getMetered()); + + // Explicitly expect 0, as documented in Javadoc on setter methods. + assertEquals(0, networkPriority.getMinEntryUpstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinExitUpstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinEntryDownstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinExitDownstreamBandwidthKbps()); + assertEquals(new HashSet(), networkPriority.getOperatorPlmnIds()); assertEquals(new HashSet(), networkPriority.getSimSpecificCarrierIds()); assertEquals(MATCH_ANY, networkPriority.getRoaming()); assertEquals(MATCH_ANY, networkPriority.getOpportunistic()); } + @Test + public void testBuilderRequiresStricterEntryCriteria() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder() + .setMinUpstreamBandwidthKbps( + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS); + + fail("Expected IAE for exit threshold > entry threshold"); + } catch (IllegalArgumentException expected) { + } + + try { + new VcnCellUnderlyingNetworkTemplate.Builder() + .setMinDownstreamBandwidthKbps( + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS); + + fail("Expected IAE for exit threshold > entry threshold"); + } catch (IllegalArgumentException expected) { + } + } + @Test public void testPersistableBundle() { final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java new file mode 100644 index 0000000000..399e136004 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java @@ -0,0 +1,24 @@ +/* + * 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 android.net.vcn; + +public class VcnUnderlyingNetworkTemplateTestBase { + // Public for use in NetworkPriorityClassifierTest + public static final int TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS = 200; + public static final int TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS = 100; + public static final int TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS = 400; + public static final int TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS = 300; +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java index cb5b47bbdc..4063178e00 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java @@ -17,8 +17,6 @@ package android.net.vcn; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -28,15 +26,19 @@ import org.junit.Test; import java.util.Set; -public class VcnWifiUnderlyingNetworkTemplateTest { +public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final String SSID = "TestWifi"; - private static final int INVALID_NETWORK_QUALITY = -1; // Package private for use in VcnGatewayConnectionConfigTest static VcnWifiUnderlyingNetworkTemplate getTestNetworkTemplate() { return new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .setMetered(MATCH_FORBIDDEN) + .setMinUpstreamBandwidthKbps( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS) + .setMinDownstreamBandwidthKbps( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .setSsids(Set.of(SSID)) .build(); } @@ -44,8 +46,19 @@ public class VcnWifiUnderlyingNetworkTemplateTest { @Test public void testBuilderAndGetters() { final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); - assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality()); assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered()); + assertEquals( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinEntryUpstreamBandwidthKbps()); + assertEquals( + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinExitUpstreamBandwidthKbps()); + assertEquals( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinEntryDownstreamBandwidthKbps()); + assertEquals( + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + networkPriority.getMinExitDownstreamBandwidthKbps()); assertEquals(Set.of(SSID), networkPriority.getSsids()); } @@ -53,18 +66,37 @@ public class VcnWifiUnderlyingNetworkTemplateTest { public void testBuilderAndGettersForDefaultValues() { final VcnWifiUnderlyingNetworkTemplate networkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder().build(); - assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality()); assertEquals(MATCH_ANY, networkPriority.getMetered()); + + // Explicitly expect 0, as documented in Javadoc on setter methods.. + assertEquals(0, networkPriority.getMinEntryUpstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinExitUpstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinEntryDownstreamBandwidthKbps()); + assertEquals(0, networkPriority.getMinExitDownstreamBandwidthKbps()); + assertTrue(networkPriority.getSsids().isEmpty()); } @Test - public void testBuildWithInvalidNetworkQuality() { + public void testBuilderRequiresStricterEntryCriteria() { try { new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(INVALID_NETWORK_QUALITY); - fail("Expected to fail due to the invalid network quality"); - } catch (Exception expected) { + .setMinUpstreamBandwidthKbps( + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS); + + fail("Expected IAE for exit threshold > entry threshold"); + } catch (IllegalArgumentException expected) { + } + + try { + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMinDownstreamBandwidthKbps( + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS); + + fail("Expected IAE for exit threshold > entry threshold"); + } catch (IllegalArgumentException expected) { } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 4bb7de8c1f..6c849b5af8 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -18,7 +18,10 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK; +import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS; +import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS; +import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS; +import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS; import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY; @@ -76,6 +79,12 @@ public class NetworkPriorityClassifierTest { private static final int CARRIER_ID = 1; private static final int CARRIER_ID_OTHER = 2; + private static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024; + private static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048; + + private static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100; + private static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200; + private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = @@ -83,6 +92,8 @@ public class NetworkPriorityClassifierTest { .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setSignalStrength(WIFI_RSSI) .setSsid(SSID) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) .build(); private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = @@ -93,6 +104,8 @@ public class NetworkPriorityClassifierTest { .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setSubscriptionIds(Set.of(SUB_ID)) .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) .build(); private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); @@ -146,7 +159,6 @@ public class NetworkPriorityClassifierTest { public void testMatchWithoutNotMeteredBit() { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) .setMetered(MATCH_FORBIDDEN) .build(); @@ -161,11 +173,133 @@ public class NetworkPriorityClassifierTest { null /* carrierConfig */)); } + private void verifyMatchesPriorityRuleForUpstreamBandwidth( + int entryUpstreamBandwidth, + int exitUpstreamBandwidth, + UnderlyingNetworkRecord currentlySelected, + boolean expectMatch) { + final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMinUpstreamBandwidthKbps(entryUpstreamBandwidth, exitUpstreamBandwidth) + .build(); + + assertEquals( + expectMatch, + checkMatchesPriorityRule( + mVcnContext, + wifiNetworkPriority, + mWifiNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot, + currentlySelected, + null /* carrierConfig */)); + } + + private void verifyMatchesPriorityRuleForDownstreamBandwidth( + int entryDownstreamBandwidth, + int exitDownstreamBandwidth, + UnderlyingNetworkRecord currentlySelected, + boolean expectMatch) { + final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMinDownstreamBandwidthKbps( + entryDownstreamBandwidth, exitDownstreamBandwidth) + .build(); + + assertEquals( + expectMatch, + checkMatchesPriorityRule( + mVcnContext, + wifiNetworkPriority, + mWifiNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot, + currentlySelected, + null /* carrierConfig */)); + } + + @Test + public void testMatchWithEntryUpstreamBandwidthEquals() { + verifyMatchesPriorityRuleForUpstreamBandwidth( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + null /* currentlySelected */, + true); + } + + @Test + public void testMatchWithEntryUpstreamBandwidthTooLow() { + verifyMatchesPriorityRuleForUpstreamBandwidth( + LINK_UPSTREAM_BANDWIDTH_KBPS + 1, + LINK_UPSTREAM_BANDWIDTH_KBPS + 1, + null /* currentlySelected */, + false); + } + + @Test + public void testMatchWithEntryDownstreamBandwidthEquals() { + verifyMatchesPriorityRuleForDownstreamBandwidth( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + null /* currentlySelected */, + true); + } + + @Test + public void testMatchWithEntryDownstreamBandwidthTooLow() { + verifyMatchesPriorityRuleForDownstreamBandwidth( + LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, + LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, + null /* currentlySelected */, + false); + } + + @Test + public void testMatchWithExitUpstreamBandwidthEquals() { + verifyMatchesPriorityRuleForUpstreamBandwidth( + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, + mWifiNetworkRecord, + true); + } + + @Test + public void testMatchWithExitUpstreamBandwidthTooLow() { + verifyMatchesPriorityRuleForUpstreamBandwidth( + LINK_UPSTREAM_BANDWIDTH_KBPS + 1, + LINK_UPSTREAM_BANDWIDTH_KBPS + 1, + mWifiNetworkRecord, + false); + } + + @Test + public void testMatchWithExitDownstreamBandwidthEquals() { + verifyMatchesPriorityRuleForDownstreamBandwidth( + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, + mWifiNetworkRecord, + true); + } + + @Test + public void testMatchWithExitDownstreamBandwidthTooLow() { + verifyMatchesPriorityRuleForDownstreamBandwidth( + LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, + LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, + mWifiNetworkRecord, + false); + } + private void verifyMatchWifi( boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) + .setMinUpstreamBandwidthKbps( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS) + .setMinDownstreamBandwidthKbps( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .build(); final UnderlyingNetworkRecord selectedNetworkRecord = isSelectedNetwork ? mWifiNetworkRecord : null; @@ -214,7 +348,12 @@ public class NetworkPriorityClassifierTest { final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER; final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() - .setNetworkQuality(NETWORK_QUALITY_OK) + .setMinUpstreamBandwidthKbps( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS) + .setMinDownstreamBandwidthKbps( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .setSsids(Set.of(nwPrioritySsid)) .build(); @@ -238,7 +377,13 @@ public class NetworkPriorityClassifierTest { } private static VcnCellUnderlyingNetworkTemplate.Builder getCellNetworkPriorityBuilder() { - return new VcnCellUnderlyingNetworkTemplate.Builder().setNetworkQuality(NETWORK_QUALITY_OK); + return new VcnCellUnderlyingNetworkTemplate.Builder() + .setMinUpstreamBandwidthKbps( + TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS) + .setMinDownstreamBandwidthKbps( + TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, + TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS); } @Test From 8246095a03f8dabf783c1258ff0af50a42dc581d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 16 Dec 2021 07:06:10 +0000 Subject: [PATCH 0304/1057] Expose entry/exit bandwidth criteria APIs for VCN templates This change adds additional criteria for bandwidth in both the upstream and downstream directions, ensuring that a minimum quality bar can be guaranteed for VCN underlying networks. Both directions support separate entry/exit criterion to allow for hysteresis. Bug: 205343355 Test: atest FrameworksVcnTests CTS-Coverage-Bug: 209498272 Change-Id: I61c8469380551e673d91f9a4428d21a40f164841 --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 78 ++++++++----------- .../net/vcn/VcnUnderlyingNetworkTemplate.java | 4 - .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 78 ++++++++----------- 3 files changed, 64 insertions(+), 96 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 44fe94ca18..69e63133eb 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -375,40 +375,33 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** - * Set the minimum accepted entry and exit upstream bandwidth allowed by this template. + * Set the minimum upstream bandwidths that this template will match. * - *

      The minimum upstream bandwidth condition allows for separate entry and exit - * thresholds, allowing for a margin of confidence before matching a network, while - * requiring a minimum bandwidth to continue being matching. In order to match this - * template, a network must fulfill one of the following two cases, depending on whether the - * network being evaluated is the Gateway Connection's underlying network: + *

      This template will not match a network that does not provide at least the bandwidth + * passed as the entry bandwidth, except in the case that the network is selected as the VCN + * Gateway Connection's underlying network, where it will continue to match until the + * bandwidth drops under the exit bandwidth. * - *

        - *
      • Network IS selected, AND the Network's estimated upstream bandwidth is greater than - * or equal to the minExitUpstreamBandwidthKbps provided. - *
      • Network IS NOT selected, AND the Network's estimated upstream bandwidth is greater - * than or equal to the minEntryUpstreamBandwidthKbps provided. - *
      - * - *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be - * unable to meet the conditions for staying selected (exit criteria), the entry criteria - * MUST be greater than, or equal to the exit criteria. + *

      The entry criteria MUST be greater than, or equal to the exit criteria to avoid the + * invalid case where a network fulfills the entry criteria, but at the same time fails the + * exit criteria. * *

      Estimated bandwidth of a network is provided by the transport layer, and reported in * {@link NetworkCapabilities}. The provided estimates will be used without modification. * - * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a - * network that IS NOT an already-selected underlying network, or {@code 0} to disable - * this requirement. MUST be greater than, or equal to minExitUpstreamBandwidthKbps. - * Defaults to {@code 0} + * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks + * that ARE NOT the already-selected underlying network, or {@code 0} to disable this + * requirement. Disabled by default. * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network * that IS the already-selected underlying network, or {@code 0} to disable this - * requirement. MUST be less than, or equal to minEntryUpstreamBandwidthKbps. Defaults - * to {@code 0} + * requirement. Disabled by default. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull + // The getter for the two integers are separated, and in the superclass. Please see {@link + // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link + // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()} + @SuppressLint("MissingGetterMatchingBuilder") public Builder setMinUpstreamBandwidthKbps( int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) { validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps); @@ -420,40 +413,33 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** - * Set the minimum acceptable downstream bandwidths allowed by this template. + * Set the minimum upstream bandwidths that this template will match. * - *

      The minimum downstream bandwidth condition allows for separate entry and exit - * thresholds, allowing for a margin of confidence before matching a network, while - * requiring a minimum bandwidth to continue being matching. In order to match this - * template, a network must fulfill one of the following two cases, depending on whether the - * network being evaluated is the Gateway Connection's underlying network: + *

      This template will not match a network that does not provide at least the bandwidth + * passed as the entry bandwidth, except in the case that the network is selected as the VCN + * Gateway Connection's underlying network, where it will continue to match until the + * bandwidth drops under the exit bandwidth. * - *

        - *
      • Network IS selected, AND the Network's estimated downstream bandwidth is greater - * than or equal to the minExitDownstreamBandwidthKbps provided. - *
      • Network IS NOT selected, AND the Network's estimated downstream bandwidth is - * greater than or equal to the minEntryDownstreamBandwidthKbps provided. - *
      - * - *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be - * unable to meet the conditions for staying selected (exit criteria), the entry criteria - * MUST be greater than, or equal to the exit criteria. + *

      The entry criteria MUST be greater than, or equal to the exit criteria to avoid the + * invalid case where a network fulfills the entry criteria, but at the same time fails the + * exit criteria. * *

      Estimated bandwidth of a network is provided by the transport layer, and reported in * {@link NetworkCapabilities}. The provided estimates will be used without modification. * - * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a - * network that IS NOT an already-selected underlying network, or {@code 0} to disable - * this requirement. MUST be greater than, or equal to minExitDownstreamBandwidthKbps. - * Defaults to {@code 0} + * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for + * networks that ARE NOT the already-selected underlying network, or {@code 0} to + * disable this requirement. Disabled by default. * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a * network that IS the already-selected underlying network, or {@code 0} to disable this - * requirement. MUST be less than, or equal to minEntryDownstreamBandwidthKbps. Defaults - * to {@code 0} + * requirement. Disabled by default. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull + // The getter for the two integers are separated, and in the superclass. Please see {@link + // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link + // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()} + @SuppressLint("MissingGetterMatchingBuilder") public Builder setMinDownstreamBandwidthKbps( int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) { validateMinBandwidthKbps( diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index c39b24f1fc..3a9ca3edde 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -262,7 +262,6 @@ public abstract class VcnUnderlyingNetworkTemplate { * * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) - * @hide */ public int getMinEntryUpstreamBandwidthKbps() { return mMinEntryUpstreamBandwidthKbps; @@ -273,7 +272,6 @@ public abstract class VcnUnderlyingNetworkTemplate { * * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int) - * @hide */ public int getMinExitUpstreamBandwidthKbps() { return mMinExitUpstreamBandwidthKbps; @@ -284,7 +282,6 @@ public abstract class VcnUnderlyingNetworkTemplate { * * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) - * @hide */ public int getMinEntryDownstreamBandwidthKbps() { return mMinEntryDownstreamBandwidthKbps; @@ -295,7 +292,6 @@ public abstract class VcnUnderlyingNetworkTemplate { * * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int) - * @hide */ public int getMinExitDownstreamBandwidthKbps() { return mMinExitDownstreamBandwidthKbps; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 43ae8b2d92..23a07abdf0 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -211,40 +211,33 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** - * Set the minimum accepted entry and exit upstream bandwidth allowed by this template. + * Set the minimum upstream bandwidths that this template will match. * - *

      The minimum upstream bandwidth condition allows for separate entry and exit - * thresholds, allowing for a margin of confidence before matching a network, while - * requiring a minimum bandwidth to continue being matching. In order to match this - * template, a network must fulfill one of the following two cases, depending on whether the - * network being evaluated is the Gateway Connection's underlying network: + *

      This template will not match a network that does not provide at least the bandwidth + * passed as the entry bandwidth, except in the case that the network is selected as the VCN + * Gateway Connection's underlying network, where it will continue to match until the + * bandwidth drops under the exit bandwidth. * - *

        - *
      • Network IS selected, AND the Network's estimated upstream bandwidth is greater than - * or equal to the minExitUpstreamBandwidthKbps provided. - *
      • Network IS NOT selected, AND the Network's estimated upstream bandwidth is greater - * than or equal to the minEntryUpstreamBandwidthKbps provided. - *
      - * - *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be - * unable to meet the conditions for staying selected (exit criteria), the entry criteria - * MUST be greater than, or equal to the exit criteria. + *

      The entry criteria MUST be greater than, or equal to the exit criteria to avoid the + * invalid case where a network fulfills the entry criteria, but at the same time fails the + * exit criteria. * *

      Estimated bandwidth of a network is provided by the transport layer, and reported in * {@link NetworkCapabilities}. The provided estimates will be used without modification. * - * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a - * network that IS NOT an already-selected underlying network, or {@code 0} to disable - * this requirement. MUST be greater than, or equal to minExitUpstreamBandwidthKbps. - * Defaults to {@code 0} + * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks + * that ARE NOT the already-selected underlying network, or {@code 0} to disable this + * requirement. Disabled by default. * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network * that IS the already-selected underlying network, or {@code 0} to disable this - * requirement. MUST be less than, or equal to minEntryUpstreamBandwidthKbps. Defaults - * to {@code 0} + * requirement. Disabled by default. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull + // The getter for the two integers are separated, and in the superclass. Please see {@link + // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link + // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()} + @SuppressLint("MissingGetterMatchingBuilder") public Builder setMinUpstreamBandwidthKbps( int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) { validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps); @@ -256,40 +249,33 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** - * Set the minimum acceptable downstream bandwidths allowed by this template. + * Set the minimum upstream bandwidths that this template will match. * - *

      The minimum downstream bandwidth condition allows for separate entry and exit - * thresholds, allowing for a margin of confidence before matching a network, while - * requiring a minimum bandwidth to continue being matching. In order to match this - * template, a network must fulfill one of the following two cases, depending on whether the - * network being evaluated is the Gateway Connection's underlying network: + *

      This template will not match a network that does not provide at least the bandwidth + * passed as the entry bandwidth, except in the case that the network is selected as the VCN + * Gateway Connection's underlying network, where it will continue to match until the + * bandwidth drops under the exit bandwidth. * - *

        - *
      • Network IS selected, AND the Network's estimated downstream bandwidth is greater - * than or equal to the minExitDownstreamBandwidthKbps provided. - *
      • Network IS NOT selected, AND the Network's estimated downstream bandwidth is - * greater than or equal to the minEntryDownstreamBandwidthKbps provided. - *
      - * - *

      To prevent a network from being selected (fulfilling the entry criteria), and yet be - * unable to meet the conditions for staying selected (exit criteria), the entry criteria - * MUST be greater than, or equal to the exit criteria. + *

      The entry criteria MUST be greater than, or equal to the exit criteria to avoid the + * invalid case where a network fulfills the entry criteria, but at the same time fails the + * exit criteria. * *

      Estimated bandwidth of a network is provided by the transport layer, and reported in * {@link NetworkCapabilities}. The provided estimates will be used without modification. * - * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a - * network that IS NOT an already-selected underlying network, or {@code 0} to disable - * this requirement. MUST be greater than, or equal to minExitDownstreamBandwidthKbps. - * Defaults to {@code 0} + * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for + * networks that ARE NOT the already-selected underlying network, or {@code 0} to + * disable this requirement. Disabled by default. * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a * network that IS the already-selected underlying network, or {@code 0} to disable this - * requirement. MUST be less than, or equal to minEntryDownstreamBandwidthKbps. Defaults - * to {@code 0} + * requirement. Disabled by default. * @return this {@link Builder} instance, for chaining - * @hide */ @NonNull + // The getter for the two integers are separated, and in the superclass. Please see {@link + // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link + // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()} + @SuppressLint("MissingGetterMatchingBuilder") public Builder setMinDownstreamBandwidthKbps( int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) { validateMinBandwidthKbps( From 6084821b114066b00976a1419e05fb6919edb385 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Jan 2022 07:49:51 +0000 Subject: [PATCH 0305/1057] Listen for individual subscription mobile data toggles This change ensures that the VCN listens for changes on a per-subscription basis. In the DSDS case, the Settings.Global.MOBILE_DATA toggles is insufficient, as the toggles for individual subscriptions are changed instead of the global toggle. Without this patch, the VCN may ignore changes in the user toggles, and continue providing data service even after user data is disabled. Similarly, it may fail to bring up a VCN when user data is re-enabled. Bug: 214247774 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1947700 Change-Id: I1e84c25f48eab90dca163eda809fc11d5d21bc31 Merged-In: I1e84c25f48eab90dca163eda809fc11d5d21bc31 --- .../src/com/android/server/vcn/Vcn.java | 69 ++++++++- .../java/com/android/server/vcn/VcnTest.java | 132 +++++++++++++++--- 2 files changed, 175 insertions(+), 26 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index e0cc8e1820..f29c40f743 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -39,10 +39,13 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -57,6 +60,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -148,6 +152,10 @@ public class Vcn extends Handler { @NonNull private final VcnContentResolver mContentResolver; @NonNull private final ContentObserver mMobileDataSettingsObserver; + @NonNull + private final Map mMobileDataStateListeners = + new ArrayMap<>(); + /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. * @@ -221,6 +229,9 @@ public class Vcn extends Handler { // Update mIsMobileDataEnabled before starting handling of NetworkRequests. mIsMobileDataEnabled = getMobileDataStatus(); + // Register mobile data state listeners. + updateMobileDataStateListeners(); + // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -348,6 +359,12 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } + // Unregister MobileDataStateListeners + for (VcnUserMobileDataStateListener listener : mMobileDataStateListeners.values()) { + getTelephonyManager().unregisterTelephonyCallback(listener); + } + mMobileDataStateListeners.clear(); + mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } @@ -454,11 +471,40 @@ public class Vcn extends Handler { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + updateMobileDataStateListeners(); + // Update the mobile data state after updating the subscription snapshot as a change in // subIds for a subGroup may affect the mobile data state. handleMobileDataToggled(); } + private void updateMobileDataStateListeners() { + final Set subIdsInGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); + final HandlerExecutor executor = new HandlerExecutor(this); + + // Register new callbacks + for (int subId : subIdsInGroup) { + if (!mMobileDataStateListeners.containsKey(subId)) { + final VcnUserMobileDataStateListener listener = + new VcnUserMobileDataStateListener(); + + getTelephonyManagerForSubid(subId).registerTelephonyCallback(executor, listener); + mMobileDataStateListeners.put(subId, listener); + } + } + + // Unregister old callbacks + Iterator> iterator = + mMobileDataStateListeners.entrySet().iterator(); + while (iterator.hasNext()) { + final Entry entry = iterator.next(); + if (!subIdsInGroup.contains(entry.getKey())) { + getTelephonyManager().unregisterTelephonyCallback(entry.getValue()); + iterator.remove(); + } + } + } + private void handleMobileDataToggled() { final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; mIsMobileDataEnabled = getMobileDataStatus(); @@ -493,11 +539,8 @@ public class Vcn extends Handler { } private boolean getMobileDataStatus() { - final TelephonyManager genericTelMan = - mVcnContext.getContext().getSystemService(TelephonyManager.class); - for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { + if (getTelephonyManagerForSubid(subId).isDataEnabled()) { return true; } } @@ -517,6 +560,14 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } + private TelephonyManager getTelephonyManager() { + return mVcnContext.getContext().getSystemService(TelephonyManager.class); + } + + private TelephonyManager getTelephonyManagerForSubid(int subid) { + return getTelephonyManager().createForSubscriptionId(subid); + } + private String getLogPrefix() { return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -670,6 +721,16 @@ public class Vcn extends Handler { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + class VcnUserMobileDataStateListener extends TelephonyCallback + implements TelephonyCallback.UserMobileDataStateListener { + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 5d2f9d7485..6d269686e4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -58,6 +58,7 @@ import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; @@ -207,6 +208,13 @@ public class VcnTest { .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); } + @Test + public void testMobileDataStateListenersRegistered() { + // Validate state from setUp() + verify(mTelephonyManager, times(3)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + } + @Test public void testMobileDataStateCheckedOnInitialization_enabled() { // Validate state from setUp() @@ -263,6 +271,24 @@ public class VcnTest { assertFalse(mVcn.isMobileDataEnabled()); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataStateListeners() { + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + + doReturn(new ArraySet<>(Arrays.asList(2, 4))) + .when(updatedSnapshot) + .getAllSubIdsInGroup(any()); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + verify(mTelephonyManager, times(4)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + verify(mTelephonyManager, times(2)) + .unregisterTelephonyCallback(any(VcnUserMobileDataStateListener.class)); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -402,24 +428,17 @@ public class VcnTest { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } - private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { - final ArgumentCaptor captor = - ArgumentCaptor.forClass(ContentObserver.class); - verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); - final ContentObserver contentObserver = captor.getValue(); - + private void setupForMobileDataTest(boolean startingToggleState) { // Start VcnGatewayConnections final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); triggerVcnRequestListeners(requestListener); - final Map gateways = - mVcn.getVcnGatewayConnectionConfigMap(); - - // Trigger data toggle change. - doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); - contentObserver.onChange(false /* selfChange, ignored */); - mTestLooper.dispatchAll(); + } + private void verifyMobileDataToggledUpdatesGatewayConnections( + boolean startingToggleState, + boolean endingToggleState, + Map gateways) { // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the // toggle state changed. for (Entry entry : gateways.entrySet()) { @@ -433,29 +452,98 @@ public class VcnTest { } } + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); if (startingToggleState != endingToggleState) { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } - @Test - public void testMobileDataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); + private void verifyGlobalMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); } @Test - public void testMobileDataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + public void testGlobalMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testGlobalMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + } + + private void verifySubscriptionMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + final ArgumentCaptor captor = + ArgumentCaptor.forClass(VcnUserMobileDataStateListener.class); + verify(mTelephonyManager, times(3)).registerTelephonyCallback(any(), captor.capture()); + final VcnUserMobileDataStateListener listener = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + listener.onUserMobileDataStateChanged(false /* enabled, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); + } + + @Test + public void testSubscriptionMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); } } From fe137e2293f54f3f4b7f09aa7089b47bd2963d6b Mon Sep 17 00:00:00 2001 From: Joseph Jang Date: Thu, 13 Jan 2022 10:40:45 +0000 Subject: [PATCH 0306/1057] Revert "Listen for individual subscription mobile data toggles" This reverts commit 006224d9f8f267fbee0f99f8c0903c9e45b9e780. Reason for revert: Change-Id: If8ddbfe8a0a8d445c4971572cf3301ebbb816347 --- .../src/com/android/server/vcn/Vcn.java | 69 +-------- .../java/com/android/server/vcn/VcnTest.java | 132 +++--------------- 2 files changed, 26 insertions(+), 175 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index f29c40f743..e0cc8e1820 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -39,13 +39,10 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; -import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -60,7 +57,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -152,10 +148,6 @@ public class Vcn extends Handler { @NonNull private final VcnContentResolver mContentResolver; @NonNull private final ContentObserver mMobileDataSettingsObserver; - @NonNull - private final Map mMobileDataStateListeners = - new ArrayMap<>(); - /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. * @@ -229,9 +221,6 @@ public class Vcn extends Handler { // Update mIsMobileDataEnabled before starting handling of NetworkRequests. mIsMobileDataEnabled = getMobileDataStatus(); - // Register mobile data state listeners. - updateMobileDataStateListeners(); - // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -359,12 +348,6 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } - // Unregister MobileDataStateListeners - for (VcnUserMobileDataStateListener listener : mMobileDataStateListeners.values()) { - getTelephonyManager().unregisterTelephonyCallback(listener); - } - mMobileDataStateListeners.clear(); - mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } @@ -471,40 +454,11 @@ public class Vcn extends Handler { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } - updateMobileDataStateListeners(); - // Update the mobile data state after updating the subscription snapshot as a change in // subIds for a subGroup may affect the mobile data state. handleMobileDataToggled(); } - private void updateMobileDataStateListeners() { - final Set subIdsInGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); - final HandlerExecutor executor = new HandlerExecutor(this); - - // Register new callbacks - for (int subId : subIdsInGroup) { - if (!mMobileDataStateListeners.containsKey(subId)) { - final VcnUserMobileDataStateListener listener = - new VcnUserMobileDataStateListener(); - - getTelephonyManagerForSubid(subId).registerTelephonyCallback(executor, listener); - mMobileDataStateListeners.put(subId, listener); - } - } - - // Unregister old callbacks - Iterator> iterator = - mMobileDataStateListeners.entrySet().iterator(); - while (iterator.hasNext()) { - final Entry entry = iterator.next(); - if (!subIdsInGroup.contains(entry.getKey())) { - getTelephonyManager().unregisterTelephonyCallback(entry.getValue()); - iterator.remove(); - } - } - } - private void handleMobileDataToggled() { final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; mIsMobileDataEnabled = getMobileDataStatus(); @@ -539,8 +493,11 @@ public class Vcn extends Handler { } private boolean getMobileDataStatus() { + final TelephonyManager genericTelMan = + mVcnContext.getContext().getSystemService(TelephonyManager.class); + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - if (getTelephonyManagerForSubid(subId).isDataEnabled()) { + if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { return true; } } @@ -560,14 +517,6 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } - private TelephonyManager getTelephonyManager() { - return mVcnContext.getContext().getSystemService(TelephonyManager.class); - } - - private TelephonyManager getTelephonyManagerForSubid(int subid) { - return getTelephonyManager().createForSubscriptionId(subid); - } - private String getLogPrefix() { return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -721,16 +670,6 @@ public class Vcn extends Handler { } } - @VisibleForTesting(visibility = Visibility.PRIVATE) - class VcnUserMobileDataStateListener extends TelephonyCallback - implements TelephonyCallback.UserMobileDataStateListener { - - @Override - public void onUserMobileDataStateChanged(boolean enabled) { - sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); - } - } - /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 6d269686e4..5d2f9d7485 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -58,7 +58,6 @@ import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; -import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; @@ -208,13 +207,6 @@ public class VcnTest { .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); } - @Test - public void testMobileDataStateListenersRegistered() { - // Validate state from setUp() - verify(mTelephonyManager, times(3)) - .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); - } - @Test public void testMobileDataStateCheckedOnInitialization_enabled() { // Validate state from setUp() @@ -271,24 +263,6 @@ public class VcnTest { assertFalse(mVcn.isMobileDataEnabled()); } - @Test - public void testSubscriptionSnapshotUpdatesMobileDataStateListeners() { - final TelephonySubscriptionSnapshot updatedSnapshot = - mock(TelephonySubscriptionSnapshot.class); - - doReturn(new ArraySet<>(Arrays.asList(2, 4))) - .when(updatedSnapshot) - .getAllSubIdsInGroup(any()); - - mVcn.updateSubscriptionSnapshot(updatedSnapshot); - mTestLooper.dispatchAll(); - - verify(mTelephonyManager, times(4)) - .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); - verify(mTelephonyManager, times(2)) - .unregisterTelephonyCallback(any(VcnUserMobileDataStateListener.class)); - } - private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -428,17 +402,24 @@ public class VcnTest { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } - private void setupForMobileDataTest(boolean startingToggleState) { + private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + // Start VcnGatewayConnections final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); triggerVcnRequestListeners(requestListener); - } + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); - private void verifyMobileDataToggledUpdatesGatewayConnections( - boolean startingToggleState, - boolean endingToggleState, - Map gateways) { // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the // toggle state changed. for (Entry entry : gateways.entrySet()) { @@ -452,98 +433,29 @@ public class VcnTest { } } - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); if (startingToggleState != endingToggleState) { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } - private void verifyGlobalMobileDataToggled( - boolean startingToggleState, boolean endingToggleState) { - setupForMobileDataTest(startingToggleState); - final Map gateways = - mVcn.getVcnGatewayConnectionConfigMap(); - - // Trigger data toggle change - final ArgumentCaptor captor = - ArgumentCaptor.forClass(ContentObserver.class); - verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); - final ContentObserver contentObserver = captor.getValue(); - - doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); - contentObserver.onChange(false /* selfChange, ignored */); - mTestLooper.dispatchAll(); - - // Verify resultant behavior - verifyMobileDataToggledUpdatesGatewayConnections( - startingToggleState, endingToggleState, gateways); + @Test + public void testMobileDataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); } @Test - public void testGlobalMobileDataEnabled() { - verifyGlobalMobileDataToggled( - false /* startingToggleState */, true /* endingToggleState */); + public void testMobileDataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); } @Test - public void testGlobalMobileDataDisabled() { - verifyGlobalMobileDataToggled( - true /* startingToggleState */, false /* endingToggleState */); + public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); } @Test - public void testGlobalMobileDataObserverFiredWithoutChanges_dataEnabled() { - verifyGlobalMobileDataToggled( - false /* startingToggleState */, false /* endingToggleState */); - } - - @Test - public void testGlobalMobileDataObserverFiredWithoutChanges_dataDisabled() { - verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); - } - - private void verifySubscriptionMobileDataToggled( - boolean startingToggleState, boolean endingToggleState) { - setupForMobileDataTest(startingToggleState); - final Map gateways = - mVcn.getVcnGatewayConnectionConfigMap(); - - // Trigger data toggle change. - final ArgumentCaptor captor = - ArgumentCaptor.forClass(VcnUserMobileDataStateListener.class); - verify(mTelephonyManager, times(3)).registerTelephonyCallback(any(), captor.capture()); - final VcnUserMobileDataStateListener listener = captor.getValue(); - - doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); - listener.onUserMobileDataStateChanged(false /* enabled, ignored */); - mTestLooper.dispatchAll(); - - // Verify resultant behavior - verifyMobileDataToggledUpdatesGatewayConnections( - startingToggleState, endingToggleState, gateways); - } - - @Test - public void testSubscriptionMobileDataEnabled() { - verifyGlobalMobileDataToggled( - false /* startingToggleState */, true /* endingToggleState */); - } - - @Test - public void testSubscriptionMobileDataDisabled() { - verifyGlobalMobileDataToggled( - true /* startingToggleState */, false /* endingToggleState */); - } - - @Test - public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataEnabled() { - verifyGlobalMobileDataToggled( - false /* startingToggleState */, false /* endingToggleState */); - } - - @Test - public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataDisabled() { - verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); } } From a59e3098d9c6666e632abf7f0ed508f040b55f31 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 11 Jan 2022 13:24:41 -0800 Subject: [PATCH 0307/1057] Improve the API doc for setVcnUnderlyingNetworkPriorities Bug: 205343355 Test: make Change-Id: Ib1cb4b2e05f1e769b4ccb4a45b6abd7589d35a07 --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 92956e859f..734e7dc55b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -553,8 +553,8 @@ public final class VcnGatewayConnectionConfig { * networks, a network will be chosen arbitrarily amongst the networks matching the highest * priority rule. * - *

      If all networks fail to match the rules provided, an underlying network will still be - * selected (at random if necessary). + *

      If all networks fail to match the rules provided, a carrier-owned underlying network + * will still be selected (if available, at random if necessary). * * @param underlyingNetworkTemplates a list of unique VcnUnderlyingNetworkTemplates that are * ordered from most to least preferred, or an empty list to use the default From f571ca19786c999143fc72141933078305436741 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Jan 2022 18:38:17 +0000 Subject: [PATCH 0308/1057] Revert "Revert "Listen for individual subscription mobile data toggles"" This reverts commit fe137e2293f54f3f4b7f09aa7089b47bd2963d6b. Reason for revert: Build breakage could not possibly have been th caused by the initial CL. Cause was a String index overflow "Caused by: com.android.tools.r8.internal.du: String-index overflow." Tested with local build of aosp-master/full-eng, completes successfully. Change-Id: I207372c9513b450cf246874ba1d1e98dbd147f27 --- .../src/com/android/server/vcn/Vcn.java | 69 ++++++++- .../java/com/android/server/vcn/VcnTest.java | 132 +++++++++++++++--- 2 files changed, 175 insertions(+), 26 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index e0cc8e1820..f29c40f743 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -39,10 +39,13 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -57,6 +60,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -148,6 +152,10 @@ public class Vcn extends Handler { @NonNull private final VcnContentResolver mContentResolver; @NonNull private final ContentObserver mMobileDataSettingsObserver; + @NonNull + private final Map mMobileDataStateListeners = + new ArrayMap<>(); + /** * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. * @@ -221,6 +229,9 @@ public class Vcn extends Handler { // Update mIsMobileDataEnabled before starting handling of NetworkRequests. mIsMobileDataEnabled = getMobileDataStatus(); + // Register mobile data state listeners. + updateMobileDataStateListeners(); + // Register to receive cached and future NetworkRequests mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); } @@ -348,6 +359,12 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } + // Unregister MobileDataStateListeners + for (VcnUserMobileDataStateListener listener : mMobileDataStateListeners.values()) { + getTelephonyManager().unregisterTelephonyCallback(listener); + } + mMobileDataStateListeners.clear(); + mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } @@ -454,11 +471,40 @@ public class Vcn extends Handler { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + updateMobileDataStateListeners(); + // Update the mobile data state after updating the subscription snapshot as a change in // subIds for a subGroup may affect the mobile data state. handleMobileDataToggled(); } + private void updateMobileDataStateListeners() { + final Set subIdsInGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); + final HandlerExecutor executor = new HandlerExecutor(this); + + // Register new callbacks + for (int subId : subIdsInGroup) { + if (!mMobileDataStateListeners.containsKey(subId)) { + final VcnUserMobileDataStateListener listener = + new VcnUserMobileDataStateListener(); + + getTelephonyManagerForSubid(subId).registerTelephonyCallback(executor, listener); + mMobileDataStateListeners.put(subId, listener); + } + } + + // Unregister old callbacks + Iterator> iterator = + mMobileDataStateListeners.entrySet().iterator(); + while (iterator.hasNext()) { + final Entry entry = iterator.next(); + if (!subIdsInGroup.contains(entry.getKey())) { + getTelephonyManager().unregisterTelephonyCallback(entry.getValue()); + iterator.remove(); + } + } + } + private void handleMobileDataToggled() { final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled; mIsMobileDataEnabled = getMobileDataStatus(); @@ -493,11 +539,8 @@ public class Vcn extends Handler { } private boolean getMobileDataStatus() { - final TelephonyManager genericTelMan = - mVcnContext.getContext().getSystemService(TelephonyManager.class); - for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) { + if (getTelephonyManagerForSubid(subId).isDataEnabled()) { return true; } } @@ -517,6 +560,14 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } + private TelephonyManager getTelephonyManager() { + return mVcnContext.getContext().getSystemService(TelephonyManager.class); + } + + private TelephonyManager getTelephonyManagerForSubid(int subid) { + return getTelephonyManager().createForSubscriptionId(subid); + } + private String getLogPrefix() { return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -670,6 +721,16 @@ public class Vcn extends Handler { } } + @VisibleForTesting(visibility = Visibility.PRIVATE) + class VcnUserMobileDataStateListener extends TelephonyCallback + implements TelephonyCallback.UserMobileDataStateListener { + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED)); + } + } + /** External dependencies used by Vcn, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java index 5d2f9d7485..6d269686e4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnTest.java @@ -58,6 +58,7 @@ import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; import org.junit.Before; @@ -207,6 +208,13 @@ public class VcnTest { .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class)); } + @Test + public void testMobileDataStateListenersRegistered() { + // Validate state from setUp() + verify(mTelephonyManager, times(3)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + } + @Test public void testMobileDataStateCheckedOnInitialization_enabled() { // Validate state from setUp() @@ -263,6 +271,24 @@ public class VcnTest { assertFalse(mVcn.isMobileDataEnabled()); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataStateListeners() { + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + + doReturn(new ArraySet<>(Arrays.asList(2, 4))) + .when(updatedSnapshot) + .getAllSubIdsInGroup(any()); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + verify(mTelephonyManager, times(4)) + .registerTelephonyCallback(any(), any(VcnUserMobileDataStateListener.class)); + verify(mTelephonyManager, times(2)) + .unregisterTelephonyCallback(any(VcnUserMobileDataStateListener.class)); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -402,24 +428,17 @@ public class VcnTest { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } - private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) { - final ArgumentCaptor captor = - ArgumentCaptor.forClass(ContentObserver.class); - verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); - final ContentObserver contentObserver = captor.getValue(); - + private void setupForMobileDataTest(boolean startingToggleState) { // Start VcnGatewayConnections final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); triggerVcnRequestListeners(requestListener); - final Map gateways = - mVcn.getVcnGatewayConnectionConfigMap(); - - // Trigger data toggle change. - doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); - contentObserver.onChange(false /* selfChange, ignored */); - mTestLooper.dispatchAll(); + } + private void verifyMobileDataToggledUpdatesGatewayConnections( + boolean startingToggleState, + boolean endingToggleState, + Map gateways) { // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the // toggle state changed. for (Entry entry : gateways.entrySet()) { @@ -433,29 +452,98 @@ public class VcnTest { } } + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); if (startingToggleState != endingToggleState) { verify(mVcnNetworkProvider).resendAllRequests(requestListener); } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } - @Test - public void testMobileDataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */); + private void verifyGlobalMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change + final ArgumentCaptor captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + contentObserver.onChange(false /* selfChange, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); } @Test - public void testMobileDataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataEnabled() { - verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */); + public void testGlobalMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); } @Test - public void testMobileDataObserverFiredWithoutChanges_dataDisabled() { - verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + public void testGlobalMobileDataObserverFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testGlobalMobileDataObserverFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); + } + + private void verifySubscriptionMobileDataToggled( + boolean startingToggleState, boolean endingToggleState) { + setupForMobileDataTest(startingToggleState); + final Map gateways = + mVcn.getVcnGatewayConnectionConfigMap(); + + // Trigger data toggle change. + final ArgumentCaptor captor = + ArgumentCaptor.forClass(VcnUserMobileDataStateListener.class); + verify(mTelephonyManager, times(3)).registerTelephonyCallback(any(), captor.capture()); + final VcnUserMobileDataStateListener listener = captor.getValue(); + + doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled(); + listener.onUserMobileDataStateChanged(false /* enabled, ignored */); + mTestLooper.dispatchAll(); + + // Verify resultant behavior + verifyMobileDataToggledUpdatesGatewayConnections( + startingToggleState, endingToggleState, gateways); + } + + @Test + public void testSubscriptionMobileDataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, true /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataDisabled() { + verifyGlobalMobileDataToggled( + true /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataEnabled() { + verifyGlobalMobileDataToggled( + false /* startingToggleState */, false /* endingToggleState */); + } + + @Test + public void testSubscriptionMobileDataListenerFiredWithoutChanges_dataDisabled() { + verifyGlobalMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */); } } From eecb1ff29f0149a95f27ee50e3353116c4cce203 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Fri, 14 Jan 2022 17:35:36 +0000 Subject: [PATCH 0309/1057] Revert "Revert "Migrate unsafe parcel APIs in framework-minus-apex"" This reverts commit ab44f1155f87e0bd78ecb3ded6b9203ec9d6c0f7. Reintroducing ag/16366278 since it seems unrelated to b/214053959 (more details on b/214053959#comment55). Original commit message: Migrate unsafe parcel APIs in framework-minus-apex Migrate the following unsafe parcel APIs in framework-minus-apex: * Parcel.readSerializable() * Parcel.readArrayList() * Parcel.readList() * Parcel.readParcelable() * Parcel.readParcelableList() * Parcel.readSparseArray() This CL was generated by applying lint fixes that infer the expected type from the caller code and provide that as the type parameter (ag/16365240). A few observations: * In some classes we couldn't migrate because the class also belonged to another build module whose min SDK wasn't current (as is the case for framework-minus-apex), hence I suppressed the lint check (since I'll eventually submit the lint check to the tree). * In some cases, I needed to do the cast in https://stackoverflow.com/a/1080525/5765705 to make the compiler happy since there isn't another way of providing a class of type Class>. * In the readSerializable() case, the new API also requires the class loader, that was inferred to by InferredClass.class.getClassLoader(). * Note that automatic formatting and import rely on running hooked up to the IDE, which wasn't the case here. Bug: 195622897 Change-Id: I272432e6e082a973f7a50492ec35d79c2b577c93 Test: TH passes --- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java | 2 +- Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java | 2 +- .../src/android/net/vcn/VcnUnderlyingNetworkPolicy.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index caab15251f..fd3fe3731b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -173,7 +173,7 @@ public final class VcnConfig implements Parcelable { new Parcelable.Creator() { @NonNull public VcnConfig createFromParcel(Parcel in) { - return new VcnConfig((PersistableBundle) in.readParcelable(null)); + return new VcnConfig((PersistableBundle) in.readParcelable(null, android.os.PersistableBundle.class)); } @NonNull diff --git a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java index 14e70cfeb1..fca084a00a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnNetworkPolicyResult.java @@ -114,7 +114,7 @@ public final class VcnNetworkPolicyResult implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnNetworkPolicyResult createFromParcel(Parcel in) { - return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null, android.net.NetworkCapabilities.class)); } public VcnNetworkPolicyResult[] newArray(int size) { diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 25a257423c..5c47b28a7c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -146,7 +146,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); - final WifiInfo wifiInfo = in.readParcelable(null); + final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class); // If all fields are their null values, return null TransportInfo to avoid // leaking information about this being a VCN Network (instead of macro diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java index b0d4f3be24..2b5305d05d 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -106,7 +106,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null, android.net.vcn.VcnNetworkPolicyResult.class)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { From b9f7ff1e0baa49ce5aa4887784773adfb64c5149 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Dec 2021 18:54:23 -0800 Subject: [PATCH 0310/1057] Verify building VCN configurations with underlying network template Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I27d3fd5100b32b4a7fadf6a2cda41acea245cd2f --- .../VcnCellUnderlyingNetworkTemplateTest.java | 77 +++++++++++++++++++ .../cts/VcnGatewayConnectionConfigTest.java | 19 ++++- .../VcnWifiUnderlyingNetworkTemplateTest.java | 64 +++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java new file mode 100644 index 0000000000..e9ecd78fb5 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn.cts; + +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; + +import static org.junit.Assert.assertEquals; + +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +public class VcnCellUnderlyingNetworkTemplateTest { + private static final Set ALLOWED_PLMN_IDS = Set.of("123456", "234567"); + private static final Set ALLOWED_CARRIER_IDS = Set.of(100, 101); + + // Package private for use in VcnGatewayConnectionConfigTest + static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { + return new VcnCellUnderlyingNetworkTemplate.Builder() + .setMetered(MATCH_REQUIRED) + .setRoaming(MATCH_REQUIRED) + .setOpportunistic(MATCH_FORBIDDEN) + .setOperatorPlmnIds(ALLOWED_PLMN_IDS) + .setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS) + .build(); + } + + @Test + public void testBuilderAndGetters() { + final VcnCellUnderlyingNetworkTemplate networkTemplate = getTestNetworkTemplate(); + assertEquals(MATCH_REQUIRED, networkTemplate.getMetered()); + assertEquals(MATCH_REQUIRED, networkTemplate.getRoaming()); + assertEquals(MATCH_FORBIDDEN, networkTemplate.getOpportunistic()); + assertEquals(ALLOWED_PLMN_IDS, networkTemplate.getOperatorPlmnIds()); + assertEquals(ALLOWED_CARRIER_IDS, networkTemplate.getSimSpecificCarrierIds()); + } + + @Test + public void testBuilderAndGettersForDefaultValues() { + final VcnCellUnderlyingNetworkTemplate networkTemplate = + new VcnCellUnderlyingNetworkTemplate.Builder().build(); + assertEquals(MATCH_ANY, networkTemplate.getMetered()); + assertEquals(MATCH_ANY, networkTemplate.getRoaming()); + assertEquals(MATCH_ANY, networkTemplate.getOpportunistic()); + assertEquals(new HashSet(), networkTemplate.getOperatorPlmnIds()); + assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); + } + + @Test + public void testBuildWithEmptySets() { + final VcnCellUnderlyingNetworkTemplate networkTemplate = + new VcnCellUnderlyingNetworkTemplate.Builder() + .setOperatorPlmnIds(new HashSet()) + .setSimSpecificCarrierIds(new HashSet()) + .build(); + assertEquals(new HashSet(), networkTemplate.getOperatorPlmnIds()); + assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 4cc6335a34..602ad4a395 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -27,12 +27,16 @@ import static org.junit.Assert.fail; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnUnderlyingNetworkTemplate; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -46,12 +50,22 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { }; private static final int MAX_MTU = 1360; + private static final List UNDERLYING_NETWORK_TEMPLATES; + + static { + List nwTemplates = new ArrayList<>(); + nwTemplates.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); + nwTemplates.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate()); + UNDERLYING_NETWORK_TEMPLATES = Collections.unmodifiableList(nwTemplates); + } + public static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { return new VcnGatewayConnectionConfig.Builder( VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams()) .addExposedCapability(NET_CAPABILITY_INTERNET) .setRetryIntervalsMillis(RETRY_INTERNAL_MILLIS) - .setMaxMtu(MAX_MTU); + .setMaxMtu(MAX_MTU) + .setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES); } private static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { @@ -66,6 +80,9 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { assertEquals(buildTunnelConnectionParams(), gatewayConnConfig.getTunnelConnectionParams()); assertArrayEquals( new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities()); + assertEquals( + UNDERLYING_NETWORK_TEMPLATES, + gatewayConnConfig.getVcnUnderlyingNetworkPriorities()); assertArrayEquals(RETRY_INTERNAL_MILLIS, gatewayConnConfig.getRetryIntervalsMillis()); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java new file mode 100644 index 0000000000..c4061e221b --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn.cts; + +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; + +import static org.junit.Assert.assertEquals; + +import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +public class VcnWifiUnderlyingNetworkTemplateTest { + private static final Set SSIDS = Set.of("TestWifi"); + + // Package private for use in VcnGatewayConnectionConfigTest + static VcnWifiUnderlyingNetworkTemplate getTestNetworkTemplate() { + return new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMetered(MATCH_FORBIDDEN) + .setSsids(SSIDS) + .build(); + } + + @Test + public void testBuilderAndGetters() { + final VcnWifiUnderlyingNetworkTemplate networkTemplate = getTestNetworkTemplate(); + assertEquals(MATCH_FORBIDDEN, networkTemplate.getMetered()); + assertEquals(SSIDS, networkTemplate.getSsids()); + } + + @Test + public void testBuilderAndGettersForDefaultValues() { + final VcnWifiUnderlyingNetworkTemplate networkTemplate = + new VcnWifiUnderlyingNetworkTemplate.Builder().build(); + assertEquals(MATCH_ANY, networkTemplate.getMetered()); + assertEquals(new HashSet(), networkTemplate.getSsids()); + } + + @Test + public void testBuildWithEmptySets() { + final VcnWifiUnderlyingNetworkTemplate networkTemplate = + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setSsids(new HashSet()) + .build(); + assertEquals(new HashSet(), networkTemplate.getSsids()); + } +} From fc99b644da8f2e27632db195f8f11faec6f915ca Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 6 Jan 2022 17:20:41 -0800 Subject: [PATCH 0311/1057] Create verifyUnderlyingCellAndRunTest method to improve code reuse This commit creates verifyUnderlyingCellAndRunTest to include common logic of VCN setup tests. Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I471cae0d1dbb886ab79b8b0e0404cc5d70070a12 --- .../android/net/vcn/cts/VcnManagerTest.java | 172 +++++++++--------- 1 file changed, 82 insertions(+), 90 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 8376ccb460..dc8c14f796 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -424,6 +424,36 @@ public class VcnManagerTest extends VcnTestBase { + expectNotMetered); } + private interface VcnTestRunnable { + void runTest(ParcelUuid subGrp, Network cellNetwork, VcnTestNetworkCallback cellNetworkCb) + throws Exception; + } + + private void verifyUnderlyingCellAndRunTest(int subId, VcnTestRunnable test) throws Exception { + // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) + // before waiting for VCN Network. + final NetworkRequest cellNetworkReq = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); + mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); + final Network cellNetwork = cellNetworkCb.waitForAvailable(); + assertNotNull("No cell network found", cellNetwork); + + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup( + mContext, + subId, + (subGrp) -> { + test.runTest(subGrp, cellNetwork, cellNetworkCb); + } + ); + }); + mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + } + @Test public void testSetVcnConfigOnTestNetwork() throws Exception { final int subId = verifyAndGetValidDataSubId(); @@ -437,27 +467,14 @@ public class VcnManagerTest extends VcnTestBase { LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); - // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before - // waiting for VCN Network. - final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); - mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); - final Network cellNetwork = cellNetworkCb.waitForAvailable(); - assertNotNull("No cell network found", cellNetwork); + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { - SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); - }); - }); - - mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + }); } private Network setupAndGetVcnNetwork( @@ -560,46 +577,34 @@ public class VcnManagerTest extends VcnTestBase { LOCAL_ADDRESS); assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); - // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before - // waiting for VCN Network. - final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); - mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); - final Network cellNetwork = cellNetworkCb.waitForAvailable(); - assertNotNull("No cell network found", cellNetwork); + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { - SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + mTestNetworkWrapper.close(); + mTestNetworkWrapper.vcnNetworkCallback.waitForLost(); - mTestNetworkWrapper.close(); - mTestNetworkWrapper.vcnNetworkCallback.waitForLost(); + final TestNetworkWrapper secondaryTestNetworkWrapper = + new TestNetworkWrapper( + mContext, + TEST_NETWORK_MTU, + true /* isMetered */, + Collections.singleton(subId), + SECONDARY_LOCAL_ADDRESS); - final TestNetworkWrapper secondaryTestNetworkWrapper = - new TestNetworkWrapper( - mContext, - TEST_NETWORK_MTU, - true /* isMetered */, - Collections.singleton(subId), - SECONDARY_LOCAL_ADDRESS); + try { + assertNotNull( + "No test network found", secondaryTestNetworkWrapper.tunNetwork); - try { - assertNotNull("No test network found", secondaryTestNetworkWrapper.tunNetwork); + injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); - injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); - - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); - } finally { - secondaryTestNetworkWrapper.close(); - } - }); - }); - - mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + } finally { + secondaryTestNetworkWrapper.close(); + } + }); } private void injectAndVerifyIkeMobikePackets(@NonNull IkeTunUtils ikeTunUtils) @@ -663,45 +668,32 @@ public class VcnManagerTest extends VcnTestBase { false /* expectNotMetered */, TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before - // waiting for VCN Network. - final NetworkRequest cellNetworkReq = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback(); - mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb); - final Network cellNetwork = cellNetworkCb.waitForAvailable(); - assertNotNull("No cell network found", cellNetwork); + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { - SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + // TODO(b/191801185): use VcnStatusCallbacks to verify safemode - // TODO(b/191801185): use VcnStatusCallbacks to verify safemode + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + false /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - // Once VCN starts, the test network should lose NOT_VCN_MANAGED - waitForExpectedUnderlyingNetworkWithCapabilities( - false /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + // After VCN has started up, wait for safemode to kick in and expect the + // underlying Test Network to regain NOT_VCN_MANAGED. + waitForExpectedUnderlyingNetworkWithCapabilities( + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + SAFEMODE_TIMEOUT_MILLIS); - // After VCN has started up, wait for safemode to kick in and expect the underlying - // Test Network to regain NOT_VCN_MANAGED. - waitForExpectedUnderlyingNetworkWithCapabilities( - true /* expectNotVcnManaged */, - false /* expectNotMetered */, - SAFEMODE_TIMEOUT_MILLIS); + // Verify that VCN Network is also lost in safemode + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); - // Verify that VCN Network is also lost in safemode - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); - - mVcnManager.clearVcnConfig(subGrp); - }); - }); - - mConnectivityManager.unregisterNetworkCallback(cellNetworkCb); + mVcnManager.clearVcnConfig(subGrp); + }); } } From ec9042005892ccae760733419ce38dc9f2b332af Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 19 Jan 2022 17:13:42 -0800 Subject: [PATCH 0312/1057] Improve code reuse for tests with TestNetworkWrapper This commit defines createTestNetworkWrapper method to improve the code reusability Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I0bf18ca832e8cdb3e5941c13ec8d957796cbc1b9 --- .../android/net/vcn/cts/VcnManagerTest.java | 239 ++++++++---------- 1 file changed, 107 insertions(+), 132 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index dc8c14f796..b78512819d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -26,6 +26,7 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.internal.util.FunctionalUtils.ThrowingConsumer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -96,8 +97,6 @@ public class VcnManagerTest extends VcnTestBase { private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; - private TestNetworkWrapper mTestNetworkWrapper; - public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); mVcnManager = mContext.getSystemService(VcnManager.class); @@ -115,14 +114,7 @@ public class VcnManagerTest extends VcnTestBase { @After public void tearDown() throws Exception { - try { - if (mTestNetworkWrapper != null) { - mTestNetworkWrapper.close(); - mTestNetworkWrapper = null; - } - } finally { - getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); - } + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } private VcnConfig.Builder buildVcnConfigBase() { @@ -353,61 +345,73 @@ public class VcnManagerTest extends VcnTestBase { mVcnManager.unregisterVcnStatusCallback(callback); } - @Test - public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception { - final int subId = verifyAndGetValidDataSubId(); - - mTestNetworkWrapper = + private TestNetworkWrapper createTestNetworkWrapper( + boolean isMetered, int subId, InetAddress localAddress) throws Exception { + TestNetworkWrapper testNetworkWrapper = new TestNetworkWrapper( mContext, TEST_NETWORK_MTU, - true /* isMetered */, + isMetered, Collections.singleton(subId), - LOCAL_ADDRESS); - assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + localAddress); + assertNotNull("No test network found", testNetworkWrapper.tunNetwork); + return testNetworkWrapper; + } - // Before the VCN starts, the test network should have NOT_VCN_MANAGED - waitForExpectedUnderlyingNetworkWithCapabilities( - true /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + @Test + public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { - SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { - mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + CarrierPrivilegeUtils.withCarrierPrivilegesForShell(mContext, subId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, subId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); - // Once VCN starts, the test network should lose NOT_VCN_MANAGED - waitForExpectedUnderlyingNetworkWithCapabilities( - false /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + false /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - mVcnManager.clearVcnConfig(subGrp); + mVcnManager.clearVcnConfig(subGrp); - // After the VCN tears down, the test network should have - // NOT_VCN_MANAGED again - waitForExpectedUnderlyingNetworkWithCapabilities( - true /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + // After the VCN tears down, the test network should have + // NOT_VCN_MANAGED again + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + }); }); - }); + } } private void waitForExpectedUnderlyingNetworkWithCapabilities( - boolean expectNotVcnManaged, boolean expectNotMetered, long timeoutMillis) + TestNetworkWrapper testNetworkWrapper, + boolean expectNotVcnManaged, + boolean expectNotMetered, + long timeoutMillis) throws Exception { final long start = SystemClock.elapsedRealtime(); // Wait for NetworkCapabilities changes until they match the expected capabilities do { final CapabilitiesChangedEvent capabilitiesChangedEvent = - mTestNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged( + testNetworkWrapper.vcnNetworkCallback.waitForOnCapabilitiesChanged( timeoutMillis); assertNotNull("Failed to receive NetworkCapabilities change", capabilitiesChangedEvent); final NetworkCapabilities nc = capabilitiesChangedEvent.networkCapabilities; - if (mTestNetworkWrapper.tunNetwork.equals(capabilitiesChangedEvent.network) + if (testNetworkWrapper.tunNetwork.equals(capabilitiesChangedEvent.network) && nc.hasCapability(NET_CAPABILITY_VALIDATED) && expectNotVcnManaged == nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED) && expectNotMetered == nc.hasCapability(NET_CAPABILITY_NOT_METERED)) { @@ -417,7 +421,7 @@ public class VcnManagerTest extends VcnTestBase { fail( "Expected update for network=" - + mTestNetworkWrapper.tunNetwork.getNetId() + + testNetworkWrapper.tunNetwork.getNetId() + ". Wanted NOT_VCN_MANAGED=" + expectNotVcnManaged + " NOT_METERED=" @@ -458,29 +462,22 @@ public class VcnManagerTest extends VcnTestBase { public void testSetVcnConfigOnTestNetwork() throws Exception { final int subId = verifyAndGetValidDataSubId(); - mTestNetworkWrapper = - new TestNetworkWrapper( - mContext, - TEST_NETWORK_MTU, - true /* isMetered */, - Collections.singleton(subId), - LOCAL_ADDRESS); - assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); - verifyUnderlyingCellAndRunTest( - subId, - (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); - - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); - }); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + }); + } } private Network setupAndGetVcnNetwork( @NonNull ParcelUuid subGrp, @NonNull Network cellNetwork, - @NonNull VcnTestNetworkCallback cellNetworkCb) + @NonNull VcnTestNetworkCallback cellNetworkCb, + @NonNull TestNetworkWrapper testNetworkWrapper) throws Exception { cellNetworkCb.waitForAvailable(); mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); @@ -490,7 +487,7 @@ public class VcnManagerTest extends VcnTestBase { final Network lostCellNetwork = cellNetworkCb.waitForLost(); assertEquals(cellNetwork, lostCellNetwork); - injectAndVerifyIkeSessionNegotiationPackets(mTestNetworkWrapper.ikeTunUtils); + injectAndVerifyIkeSessionNegotiationPackets(testNetworkWrapper.ikeTunUtils); final Network vcnNetwork = cellNetworkCb.waitForAvailable(); assertNotNull("VCN network did not come up", vcnNetwork); @@ -568,43 +565,27 @@ public class VcnManagerTest extends VcnTestBase { public void testVcnMigrationAfterNetworkDies() throws Exception { final int subId = verifyAndGetValidDataSubId(); - mTestNetworkWrapper = - new TestNetworkWrapper( - mContext, - TEST_NETWORK_MTU, - true /* isMetered */, - Collections.singleton(subId), - LOCAL_ADDRESS); - assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); - verifyUnderlyingCellAndRunTest( - subId, - (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + testNetworkWrapper.close(); + testNetworkWrapper.vcnNetworkCallback.waitForLost(); - mTestNetworkWrapper.close(); - mTestNetworkWrapper.vcnNetworkCallback.waitForLost(); + try (TestNetworkWrapper secondaryTestNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + try { + injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); - final TestNetworkWrapper secondaryTestNetworkWrapper = - new TestNetworkWrapper( - mContext, - TEST_NETWORK_MTU, - true /* isMetered */, - Collections.singleton(subId), - SECONDARY_LOCAL_ADDRESS); - - try { - assertNotNull( - "No test network found", secondaryTestNetworkWrapper.tunNetwork); - - injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); - - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); - } finally { - secondaryTestNetworkWrapper.close(); - } - }); + clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + } finally { + secondaryTestNetworkWrapper.close(); + } + } + }); + } } private void injectAndVerifyIkeMobikePackets(@NonNull IkeTunUtils ikeTunUtils) @@ -653,47 +634,41 @@ public class VcnManagerTest extends VcnTestBase { public void testVcnSafemodeOnTestNetwork() throws Exception { final int subId = verifyAndGetValidDataSubId(); - mTestNetworkWrapper = - new TestNetworkWrapper( - mContext, - TEST_NETWORK_MTU, - true /* isMetered */, - Collections.singleton(subId), - LOCAL_ADDRESS); - assertNotNull("No test network found", mTestNetworkWrapper.tunNetwork); + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + // Before the VCN starts, the test network should have NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final Network vcnNetwork = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); - // Before the VCN starts, the test network should have NOT_VCN_MANAGED - waitForExpectedUnderlyingNetworkWithCapabilities( - true /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + // TODO(b/191801185): use VcnStatusCallbacks to verify safemode - verifyUnderlyingCellAndRunTest( - subId, - (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = - setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb); + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + false /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); - // TODO(b/191801185): use VcnStatusCallbacks to verify safemode + // After VCN has started up, wait for safemode to kick in and expect the + // underlying Test Network to regain NOT_VCN_MANAGED. + waitForExpectedUnderlyingNetworkWithCapabilities( + testNetworkWrapper, + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + SAFEMODE_TIMEOUT_MILLIS); - // Once VCN starts, the test network should lose NOT_VCN_MANAGED - waitForExpectedUnderlyingNetworkWithCapabilities( - false /* expectNotVcnManaged */, - false /* expectNotMetered */, - TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + // Verify that VCN Network is also lost in safemode + final Network lostVcnNetwork = cellNetworkCb.waitForLost(); + assertEquals(vcnNetwork, lostVcnNetwork); - // After VCN has started up, wait for safemode to kick in and expect the - // underlying Test Network to regain NOT_VCN_MANAGED. - waitForExpectedUnderlyingNetworkWithCapabilities( - true /* expectNotVcnManaged */, - false /* expectNotMetered */, - SAFEMODE_TIMEOUT_MILLIS); - - // Verify that VCN Network is also lost in safemode - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); - - mVcnManager.clearVcnConfig(subGrp); - }); + mVcnManager.clearVcnConfig(subGrp); + }); + } } } From 60af292c142e488697b4cc7f06eb1e37ae89b3e4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 27 Jan 2022 16:51:54 -0800 Subject: [PATCH 0313/1057] Test building VcnUnderlyingNetworkTemplate with bandwidths Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I8b2d34e4b157157947977e4a9abc511b365c2ab3 --- .../VcnCellUnderlyingNetworkTemplateTest.java | 31 +++++++++++- .../VcnUnderlyingNetworkTemplateTestBase.java | 48 +++++++++++++++++++ .../VcnWifiUnderlyingNetworkTemplateTest.java | 31 +++++++++++- 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnUnderlyingNetworkTemplateTestBase.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java index e9ecd78fb5..3ecf4c08bd 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java @@ -20,6 +20,7 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; @@ -28,7 +29,7 @@ import org.junit.Test; import java.util.HashSet; import java.util.Set; -public class VcnCellUnderlyingNetworkTemplateTest { +public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final Set ALLOWED_PLMN_IDS = Set.of("123456", "234567"); private static final Set ALLOWED_CARRIER_IDS = Set.of(100, 101); @@ -40,6 +41,10 @@ public class VcnCellUnderlyingNetworkTemplateTest { .setOpportunistic(MATCH_FORBIDDEN) .setOperatorPlmnIds(ALLOWED_PLMN_IDS) .setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS) + .setMinDownstreamBandwidthKbps( + MIN_ENTRY_DOWN_BANDWIDTH_KBPS, MIN_EXIT_DOWN_BANDWIDTH_KBPS) + .setMinUpstreamBandwidthKbps( + MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_EXIT_UP_BANDWIDTH_KBPS) .build(); } @@ -51,6 +56,7 @@ public class VcnCellUnderlyingNetworkTemplateTest { assertEquals(MATCH_FORBIDDEN, networkTemplate.getOpportunistic()); assertEquals(ALLOWED_PLMN_IDS, networkTemplate.getOperatorPlmnIds()); assertEquals(ALLOWED_CARRIER_IDS, networkTemplate.getSimSpecificCarrierIds()); + verifyBandwidthsWithTestValues(networkTemplate); } @Test @@ -62,6 +68,7 @@ public class VcnCellUnderlyingNetworkTemplateTest { assertEquals(MATCH_ANY, networkTemplate.getOpportunistic()); assertEquals(new HashSet(), networkTemplate.getOperatorPlmnIds()); assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); + verifyBandwidthsWithDefaultValues(networkTemplate); } @Test @@ -74,4 +81,26 @@ public class VcnCellUnderlyingNetworkTemplateTest { assertEquals(new HashSet(), networkTemplate.getOperatorPlmnIds()); assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); } + + @Test + public void testBuildWithInvalidDownstreamBandwidth() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder() + .setMinDownstreamBandwidthKbps( + MIN_ENTRY_DOWN_BANDWIDTH_KBPS, MIN_ENTRY_DOWN_BANDWIDTH_KBPS + 1); + fail("Expect to fail because entry bandwidth is smaller than exit bandwidth"); + } catch (Exception expected) { + } + } + + @Test + public void testBuildWithInvalidUpstreamBandwidth() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder() + .setMinUpstreamBandwidthKbps( + MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_ENTRY_UP_BANDWIDTH_KBPS + 1); + fail("Expect to fail because entry bandwidth is smaller than exit bandwidth"); + } catch (Exception expected) { + } + } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnUnderlyingNetworkTemplateTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnUnderlyingNetworkTemplateTestBase.java new file mode 100644 index 0000000000..fccc996376 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnUnderlyingNetworkTemplateTestBase.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn.cts; + +import static org.junit.Assert.assertEquals; + +import android.net.vcn.VcnUnderlyingNetworkTemplate; + +public class VcnUnderlyingNetworkTemplateTestBase { + protected static final int MIN_ENTRY_DOWN_BANDWIDTH_KBPS = 4000; + protected static final int MIN_EXIT_DOWN_BANDWIDTH_KBPS = 3000; + protected static final int MIN_ENTRY_UP_BANDWIDTH_KBPS = 2000; + protected static final int MIN_EXIT_UP_BANDWIDTH_KBPS = 1000; + + protected static void verifyBandwidthsWithTestValues( + VcnUnderlyingNetworkTemplate networkTemplate) { + assertEquals( + MIN_ENTRY_DOWN_BANDWIDTH_KBPS, + networkTemplate.getMinEntryDownstreamBandwidthKbps()); + assertEquals( + MIN_EXIT_DOWN_BANDWIDTH_KBPS, networkTemplate.getMinExitDownstreamBandwidthKbps()); + assertEquals( + MIN_ENTRY_UP_BANDWIDTH_KBPS, networkTemplate.getMinEntryUpstreamBandwidthKbps()); + assertEquals(MIN_EXIT_UP_BANDWIDTH_KBPS, networkTemplate.getMinExitUpstreamBandwidthKbps()); + } + + protected static void verifyBandwidthsWithDefaultValues( + VcnUnderlyingNetworkTemplate networkTemplate) { + assertEquals(0, networkTemplate.getMinEntryDownstreamBandwidthKbps()); + assertEquals(0, networkTemplate.getMinEntryDownstreamBandwidthKbps()); + assertEquals(0, networkTemplate.getMinEntryUpstreamBandwidthKbps()); + assertEquals(0, networkTemplate.getMinEntryUpstreamBandwidthKbps()); + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java index c4061e221b..fa07d784f6 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java @@ -19,6 +19,7 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; @@ -27,7 +28,7 @@ import org.junit.Test; import java.util.HashSet; import java.util.Set; -public class VcnWifiUnderlyingNetworkTemplateTest { +public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final Set SSIDS = Set.of("TestWifi"); // Package private for use in VcnGatewayConnectionConfigTest @@ -35,6 +36,10 @@ public class VcnWifiUnderlyingNetworkTemplateTest { return new VcnWifiUnderlyingNetworkTemplate.Builder() .setMetered(MATCH_FORBIDDEN) .setSsids(SSIDS) + .setMinDownstreamBandwidthKbps( + MIN_ENTRY_DOWN_BANDWIDTH_KBPS, MIN_EXIT_DOWN_BANDWIDTH_KBPS) + .setMinUpstreamBandwidthKbps( + MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_EXIT_UP_BANDWIDTH_KBPS) .build(); } @@ -43,6 +48,7 @@ public class VcnWifiUnderlyingNetworkTemplateTest { final VcnWifiUnderlyingNetworkTemplate networkTemplate = getTestNetworkTemplate(); assertEquals(MATCH_FORBIDDEN, networkTemplate.getMetered()); assertEquals(SSIDS, networkTemplate.getSsids()); + verifyBandwidthsWithTestValues(networkTemplate); } @Test @@ -51,6 +57,7 @@ public class VcnWifiUnderlyingNetworkTemplateTest { new VcnWifiUnderlyingNetworkTemplate.Builder().build(); assertEquals(MATCH_ANY, networkTemplate.getMetered()); assertEquals(new HashSet(), networkTemplate.getSsids()); + verifyBandwidthsWithDefaultValues(networkTemplate); } @Test @@ -61,4 +68,26 @@ public class VcnWifiUnderlyingNetworkTemplateTest { .build(); assertEquals(new HashSet(), networkTemplate.getSsids()); } + + @Test + public void testBuildWithInvalidDownstreamBandwidth() { + try { + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMinDownstreamBandwidthKbps( + MIN_ENTRY_DOWN_BANDWIDTH_KBPS, MIN_ENTRY_DOWN_BANDWIDTH_KBPS + 1); + fail("Expect to fail because entry bandwidth is smaller than exit bandwidth"); + } catch (Exception expected) { + } + } + + @Test + public void testBuildWithInvalidUpstreamBandwidth() { + try { + new VcnWifiUnderlyingNetworkTemplate.Builder() + .setMinUpstreamBandwidthKbps( + MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_ENTRY_UP_BANDWIDTH_KBPS + 1); + fail("Expect to fail because entry bandwidth is smaller than exit bandwidth"); + } catch (Exception expected) { + } + } } From 7abb257af5099ccd3270efd042eadebc46580d4b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 6 Jan 2022 18:24:40 -0800 Subject: [PATCH 0314/1057] Test selecting VCN underlying network according to configurations Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I2d4b6e5e85e886e6ab572f62dfbe950f82a2567b --- .../android/net/vcn/cts/VcnManagerTest.java | 229 ++++++++++++++++-- .../src/android/net/vcn/cts/VcnTestBase.java | 9 +- 2 files changed, 219 insertions(+), 19 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index b78512819d..f3703d9274 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -17,16 +17,19 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; -import static com.android.internal.util.FunctionalUtils.ThrowingConsumer; +import static com.android.internal.util.HexDump.hexStringToByteArray; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -48,6 +51,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; @@ -66,7 +71,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -118,12 +125,17 @@ public class VcnManagerTest extends VcnTestBase { } private VcnConfig.Builder buildVcnConfigBase() { + return buildVcnConfigBase(new ArrayList()); + } + + private VcnConfig.Builder buildVcnConfigBase(List nwTemplate) { // TODO(b/191371669): remove the exposed MMS capability and use // VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig() instead return new VcnConfig.Builder(mContext) .addGatewayConnectionConfig( VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase() .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .setVcnUnderlyingNetworkPriorities(nwTemplate) .build()); } @@ -465,36 +477,190 @@ public class VcnManagerTest extends VcnTestBase { try (TestNetworkWrapper testNetworkWrapper = createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = + final VcnSetupResult vcnSetupResult = setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); }); } } - private Network setupAndGetVcnNetwork( + private VcnConfig createVcnConfigPrefersMetered() throws Exception { + final List nwTemplates = new ArrayList<>(); + nwTemplates.add( + new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_REQUIRED).build()); + nwTemplates.add( + new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_FORBIDDEN).build()); + return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + } + + @Test + public void testVcnMigratesToPreferredUnderlyingNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); + + // Start on NOT_METERED, less preferred network. + try (TestNetworkWrapper testNetworkWrapperNotMetered = + createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperNotMetered); + + // Then bring up a more preferred network, and expect to switch to it. + try (TestNetworkWrapper testNetworkWrapperMetered = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + injectAndVerifyIkeMobikePackets(testNetworkWrapperMetered.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + + @Test + public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); + + // Start on METERED, more preferred network + try (TestNetworkWrapper testNetworkWrapperMetered = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperMetered); + + // Then bring up a less preferred network, and expect the VCN underlying + // network does not change. + try (TestNetworkWrapper testNetworkWrapperNotMetered = + createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { + injectAndVerifyIkeDpdPackets( + testNetworkWrapperMetered.ikeTunUtils, + vcnSetupResult.ikeExchangePortPair); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + + @Test + public void testVcnMigratesAfterPreferredUnderlyingNetworkDies() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); + + // Start on METERED, more preferred network + try (TestNetworkWrapper testNetworkWrapperMetered = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperMetered); + + // Bring up a NOT_METERED, less preferred network + try (TestNetworkWrapper testNetworkWrapperNotMetered = + createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { + // Teardown the preferred network + testNetworkWrapperMetered.close(); + testNetworkWrapperMetered.vcnNetworkCallback.waitForLost(); + + // Verify the VCN switches to the remaining NOT_METERED network + injectAndVerifyIkeMobikePackets(testNetworkWrapperNotMetered.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + + @Test + public void testVcnNoUnderlyingNetworkSelectedFallback() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final List nwTemplates = new ArrayList<>(); + nwTemplates.add( + new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_REQUIRED).build()); + final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + + // Bring up a network that does not match any of the configured network templates + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + // Verify the VCN can still be set up on the only one underlying network + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapper); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + }); + } + } + + private static class VcnSetupResult { + public final Network vcnNetwork; + public final PortPair ikeExchangePortPair; + + VcnSetupResult(Network vcnNetwork, PortPair ikeExchangePortPair) { + this.vcnNetwork = vcnNetwork; + this.ikeExchangePortPair = ikeExchangePortPair; + } + } + + private VcnSetupResult setupAndGetVcnNetwork( @NonNull ParcelUuid subGrp, @NonNull Network cellNetwork, @NonNull VcnTestNetworkCallback cellNetworkCb, + @NonNull VcnConfig testModeVcnConfig, @NonNull TestNetworkWrapper testNetworkWrapper) throws Exception { cellNetworkCb.waitForAvailable(); - mVcnManager.setVcnConfig(subGrp, buildTestModeVcnConfig()); + mVcnManager.setVcnConfig(subGrp, testModeVcnConfig); // Wait until the cell Network is lost (due to losing NOT_VCN_MANAGED) to wait for // VCN network final Network lostCellNetwork = cellNetworkCb.waitForLost(); assertEquals(cellNetwork, lostCellNetwork); - injectAndVerifyIkeSessionNegotiationPackets(testNetworkWrapper.ikeTunUtils); + final PortPair ikeExchangePortPair = + injectAndVerifyIkeSessionNegotiationPackets(testNetworkWrapper.ikeTunUtils); final Network vcnNetwork = cellNetworkCb.waitForAvailable(); assertNotNull("VCN network did not come up", vcnNetwork); - return vcnNetwork; + return new VcnSetupResult(vcnNetwork, ikeExchangePortPair); } - private void injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) + private VcnSetupResult setupAndGetVcnNetwork( + @NonNull ParcelUuid subGrp, + @NonNull Network cellNetwork, + @NonNull VcnTestNetworkCallback cellNetworkCb, + @NonNull TestNetworkWrapper testNetworkWrapper) + throws Exception { + return setupAndGetVcnNetwork( + subGrp, cellNetwork, cellNetworkCb, buildTestModeVcnConfig(), testNetworkWrapper); + } + + private PortPair injectAndVerifyIkeSessionNegotiationPackets(@NonNull IkeTunUtils ikeTunUtils) throws Exception { // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and // capturing IKE packets with a live server. @@ -530,11 +696,14 @@ public class VcnManagerTest extends VcnTestBase { false /* expectedUseEncap */, ikeInitResp); - ikeTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 1 /* expectedMsgId */, - true /* expectedUseEncap */, - ikeAuthResp); + byte[] ikeAuthReqPkt = + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthResp); + + return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt); } private void clearVcnConfigsAndVerifyNetworkTeardown( @@ -568,7 +737,7 @@ public class VcnManagerTest extends VcnTestBase { try (TestNetworkWrapper testNetworkWrapper = createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = + final VcnSetupResult vcnSetupResult = setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); testNetworkWrapper.close(); @@ -579,7 +748,8 @@ public class VcnManagerTest extends VcnTestBase { try { injectAndVerifyIkeMobikePackets(secondaryTestNetworkWrapper.ikeTunUtils); - clearVcnConfigsAndVerifyNetworkTeardown(subGrp, cellNetworkCb, vcnNetwork); + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); } finally { secondaryTestNetworkWrapper.close(); } @@ -630,6 +800,31 @@ public class VcnManagerTest extends VcnTestBase { ikeDeleteChildResp); } + private void injectAndVerifyIkeDpdPackets( + @NonNull IkeTunUtils ikeTunUtils, PortPair localRemotePorts) throws Exception { + // Generated by forcing IKE to use Test Mode (RandomnessFactory#mIsTestModeEnabled) and + // capturing IKE packets with a live server. + final String ikeDpdRequestHex = + "46b8eca1e0d72a189b9f8e0158e1c0a52E202500000000000000004c00000030" + + "3A31D5FAC230FEA67246B0C1A049A28944C341301979EB7B52FC669274B77D5F" + + "A6CFE8D768CF390536436D08"; + + byte[] ikeDpdRequest = + IkeTunUtils.buildIkePacket( + REMOTE_ADDRESS, + LOCAL_ADDRESS, + localRemotePorts.dstPort, + localRemotePorts.srcPort, + true /* useEncap */, + hexStringToByteArray(ikeDpdRequestHex)); + + ikeTunUtils.injectPacket(ikeDpdRequest); + ikeTunUtils.awaitResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + true /* expectedUseEncap */); + } + @Test public void testVcnSafemodeOnTestNetwork() throws Exception { final int subId = verifyAndGetValidDataSubId(); @@ -643,7 +838,7 @@ public class VcnManagerTest extends VcnTestBase { false /* expectNotMetered */, TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final Network vcnNetwork = + final VcnSetupResult vcnSetupResult = setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); // TODO(b/191801185): use VcnStatusCallbacks to verify safemode @@ -665,7 +860,7 @@ public class VcnManagerTest extends VcnTestBase { // Verify that VCN Network is also lost in safemode final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnNetwork, lostVcnNetwork); + assertEquals(vcnSetupResult.vcnNetwork, lostVcnNetwork); mVcnManager.clearVcnConfig(subGrp); }); diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java index d7485b13c4..ce48e2d6f0 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTestBase.java @@ -24,6 +24,7 @@ import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC; +import android.net.InetAddresses; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSaProposal; @@ -31,7 +32,12 @@ import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import java.net.InetAddress; + public class VcnTestBase { + protected static final InetAddress REMOTE_ADDRESS = + InetAddresses.parseNumericAddress("192.0.2.1"); + protected static IkeTunnelConnectionParams buildTunnelConnectionParams() { final IkeSessionParams ikeParams = getIkeSessionParamsBase().build(); return buildTunnelConnectionParams(ikeParams); @@ -61,13 +67,12 @@ public class VcnTestBase { .build(); // TODO: b/192610392 Improve VcnManagerTest CTS by adding IPv6 test case. - final String serverHostname = "192.0.2.1"; final String testLocalId = "client.test.ike.android.net"; final String testRemoteId = "server.test.ike.android.net"; final byte[] psk = "ikeAndroidPsk".getBytes(); return new IkeSessionParams.Builder() - .setServerHostname(serverHostname) + .setServerHostname(REMOTE_ADDRESS.getHostAddress()) .addSaProposal(ikeProposal) .setLocalIdentification(new IkeFqdnIdentification(testLocalId)) .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId)) From 0fc44d8f94aba0576cb7c15913ce95024fcde32c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 28 Jan 2022 17:20:30 -0800 Subject: [PATCH 0315/1057] Verify network template Builder will throw for invalid arguments Bug: 209498272 Test: atest CtsVcnTestCases Change-Id: I0d5a9def42e8135ba40757e55e97f36c84e99a2c --- .../VcnCellUnderlyingNetworkTemplateTest.java | 35 ++++++++++++++++++- .../VcnWifiUnderlyingNetworkTemplateTest.java | 9 +++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java index 3ecf4c08bd..9100bc079d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java @@ -30,7 +30,7 @@ import java.util.HashSet; import java.util.Set; public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { - private static final Set ALLOWED_PLMN_IDS = Set.of("123456", "234567"); + private static final Set ALLOWED_PLMN_IDS = Set.of("123456", "12345"); private static final Set ALLOWED_CARRIER_IDS = Set.of(100, 101); // Package private for use in VcnGatewayConnectionConfigTest @@ -82,6 +82,39 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); } + @Test + public void testBuildWithNullOperatorPlmnIds() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder().setOperatorPlmnIds(null); + fail("Expect to fail due to the null argument"); + } catch (Exception expected) { + } + } + + private static void verifyBuildWithInvalidOperatorPlmnIds(String plmnId) { + try { + new VcnCellUnderlyingNetworkTemplate.Builder().setOperatorPlmnIds(Set.of(plmnId)); + fail("Expect to fail due to the invalid PLMN ID"); + } catch (Exception expected) { + } + } + + @Test + public void testBuildWithInvalidOperatorPlmnIds() { + verifyBuildWithInvalidOperatorPlmnIds("1234567"); + verifyBuildWithInvalidOperatorPlmnIds("1234"); + verifyBuildWithInvalidOperatorPlmnIds("abcde"); + } + + @Test + public void testBuildWithNullCarrierIds() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder().setSimSpecificCarrierIds(null); + fail("Expect to fail due to the null argument"); + } catch (Exception expected) { + } + } + @Test public void testBuildWithInvalidDownstreamBandwidth() { try { diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java index fa07d784f6..d14dcf4896 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java @@ -69,6 +69,15 @@ public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe assertEquals(new HashSet(), networkTemplate.getSsids()); } + @Test + public void testBuildWithNullSsids() { + try { + new VcnWifiUnderlyingNetworkTemplate.Builder().setSsids(null); + fail("Expect to fail due to the null argument"); + } catch (Exception expected) { + } + } + @Test public void testBuildWithInvalidDownstreamBandwidth() { try { From 7893ccacb56515d3dbc02b3b07e798e9ccebb5d6 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 26 Jan 2022 00:37:52 +0800 Subject: [PATCH 0316/1057] Have FrameworksVcnTests access hidden API Bug: 204153604 Test: build, FrameworksVcnTests Change-Id: I2e92f27b4d10612d9000c0fc0d5866dd0313a336 --- Vcn/tests/unit/Android.bp | 2 ++ Vcn/tests/unit/AndroidManifest.xml | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 41f73cd9c7..228520e854 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -18,6 +18,7 @@ android_test { "java/**/*.kt", ], platform_apis: true, + defaults: ["framework-connectivity-test-defaults"], test_suites: ["device-tests"], certificate: "platform", static_libs: [ @@ -28,6 +29,7 @@ android_test { "net-tests-utils", "platform-test-annotations", "services.core", + "service-connectivity-tiramisu-pre-jarjar", ], libs: [ "android.test.runner", diff --git a/Vcn/tests/unit/AndroidManifest.xml b/Vcn/tests/unit/AndroidManifest.xml index 2ad9aac670..a8f657c89f 100644 --- a/Vcn/tests/unit/AndroidManifest.xml +++ b/Vcn/tests/unit/AndroidManifest.xml @@ -16,7 +16,8 @@ - + From b1b0bd9ec23232855eece11fe47c74b24d6bd38b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 2 Feb 2022 18:37:39 +0000 Subject: [PATCH 0317/1057] Fix potential for dead binders when calling callbacks This patch ensures that all callbacks out of the VcnManagementService are try/catch guarded to ensure that callbacks are not called and throw an exception. This is triggered when telephony dies, which results in the subscriptions changing, and attempting to notify the policy listeners triggers a DeadObjectException. Bug: 217537578 Test: atest FrameworksVcnTests Change-Id: Ibfe82fb187b7989164e22919a72b8c36d2655902 --- .../android/server/VcnManagementService.java | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 6a7afd90dc..2d328d8b09 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -539,7 +539,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void notifyAllPolicyListenersLocked() { for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) { - Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged()); + Binder.withCleanCallingIdentity(() -> { + try { + policyListener.mListener.onPolicyChanged(); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } @@ -548,8 +554,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, subGroup)) { - Binder.withCleanCallingIdentity( - () -> cbInfo.mCallback.onVcnStatusChanged(statusCode)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onVcnStatusChanged(statusCode); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } @@ -1222,13 +1233,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, mSubGroup)) { - Binder.withCleanCallingIdentity( - () -> - cbInfo.mCallback.onGatewayConnectionError( - gatewayConnectionName, - errorCode, - exceptionClass, - exceptionMessage)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onGatewayConnectionError( + gatewayConnectionName, + errorCode, + exceptionClass, + exceptionMessage); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } From 630585a77946f20f6111a66d60dcf8a3ba6a9113 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 3 Feb 2022 04:12:40 +0000 Subject: [PATCH 0318/1057] Fix potential for dead binders when calling callbacks This patch ensures that all callbacks out of the VcnManagementService are try/catch guarded to ensure that callbacks are not called and throw an exception. This is triggered when telephony dies, which results in the subscriptions changing, and attempting to notify the policy listeners triggers a DeadObjectException. Bug: 217537578 Test: atest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1969041 Change-Id: Ibfe82fb187b7989164e22919a72b8c36d2655902 Merged-In: Ibfe82fb187b7989164e22919a72b8c36d2655902 --- .../android/server/VcnManagementService.java | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index b068f86ff0..ce74f1f4a1 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -567,7 +567,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void notifyAllPolicyListenersLocked() { for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) { - Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged()); + Binder.withCleanCallingIdentity(() -> { + try { + policyListener.mListener.onPolicyChanged(); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } @@ -576,8 +582,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, subGroup)) { - Binder.withCleanCallingIdentity( - () -> cbInfo.mCallback.onVcnStatusChanged(statusCode)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onVcnStatusChanged(statusCode); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } @@ -1250,13 +1261,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, mSubGroup)) { - Binder.withCleanCallingIdentity( - () -> - cbInfo.mCallback.onGatewayConnectionError( - gatewayConnectionName, - errorCode, - exceptionClass, - exceptionMessage)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onGatewayConnectionError( + gatewayConnectionName, + errorCode, + exceptionClass, + exceptionMessage); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } From 2ddf2093a8165fed8f6cb037d5459e76c7051624 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 9 Nov 2021 20:16:34 +0000 Subject: [PATCH 0319/1057] Pull underlying network MTU using Java APIs This change ensures that if the VCN's underlying network MTU is not reported via the LinkProperties APIs (as in the case of Carrier WiFi), the kernel values will be used (as possible). Bug: 204813618 Test: Manual testing Test: atest FrameworksVcnTests CtsVcnTestCases Original-Change: https://android-review.googlesource.com/1877796 Change-Id: If291aa6b915e4da39152a679bbe3e40216b42f44 Merged-In: If291aa6b915e4da39152a679bbe3e40216b42f44 --- .../server/vcn/VcnGatewayConnection.java | 22 +++++- .../server/vcn/VcnGatewayConnectionTest.java | 70 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 51c3b33b0e..055012b1da 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -99,6 +99,7 @@ import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -2061,7 +2062,8 @@ public class VcnGatewayConnection extends StateMachine { return builder.build(); } - private static LinkProperties buildConnectedLinkProperties( + @VisibleForTesting(visibility = Visibility.PRIVATE) + LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @@ -2089,6 +2091,13 @@ public class VcnGatewayConnection extends StateMachine { lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); underlyingMtu = underlyingLp.getMtu(); + + // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result + // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by + // NetworkInterface APIs. + if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) { + underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName()); + } } else { Slog.wtf( TAG, @@ -2436,6 +2445,17 @@ public class VcnGatewayConnection extends StateMachine { public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); } + + /** Gets the MTU for the given underlying interface. */ + public int getUnderlyingIfaceMtu(String ifaceName) { + try { + final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName); + return underlyingIface == null ? 0 : underlyingIface.getMTU(); + } catch (IOException e) { + Slog.d(TAG, "Could not get MTU of underlying network", e); + return 0; + } + } } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a700171353..b8eefabea3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn; +import static android.net.IpSecManager.IpSecTunnelInterface; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -24,6 +25,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; @@ -36,8 +39,11 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.net.IpSecManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -59,8 +65,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.InetAddress; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -70,6 +79,8 @@ import java.util.UUID; public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid() + 1; + private static final String LOOPBACK_IFACE = "lo"; + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -77,6 +88,12 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map TEST_SUBID_TO_GROUP_MAP; + private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6"; + private static final int TEST_MTU = 1300; + private static final int TEST_MTU_DELTA = 64; + private static final List TEST_INTERNAL_ADDRESSES = + Arrays.asList(new LinkAddress(DUMMY_ADDR, 16)); + private static final List TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR); private static final int TEST_UPSTREAM_BANDWIDTH = 1234; private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; @@ -165,6 +182,59 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */); } + @Test + public void testBuildLinkProperties() throws Exception { + final IpSecTunnelInterface tunnelIface = + mContext.getSystemService(IpSecManager.class) + .createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); + + final LinkProperties underlyingLp = new LinkProperties(); + underlyingLp.setInterfaceName(LOOPBACK_IFACE); + underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES); + doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final VcnChildSessionConfiguration childSessionConfig = + mock(VcnChildSessionConfiguration.class); + doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses(); + doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers(); + + UnderlyingNetworkRecord record = + new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + new NetworkCapabilities.Builder().build(), + underlyingLp, + false); + + final LinkProperties vcnLp1 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + // Instead of having to recalculate the final MTU (after accounting for IPsec overhead), + // calculate another set of Link Properties with a lower MTU, and calculate the delta. + doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final LinkProperties vcnLp2 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName()); + assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses()); + assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes()); + assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu()); + } + @Test public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { verifyWakeLockSetUp(); From 0504d6c76847e16e82d3cf8b343c88fad27d6ed1 Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Thu, 3 Feb 2022 12:29:23 -0800 Subject: [PATCH 0320/1057] Monitor carrier privilege change with CarrierPrivilegesListener Monitoring carrier config change broadcast and then checking carrier privileges status is racy. The component that updates CP status (e.g. CarrierPrivilegeTracker) may monitor the same broadcast and the status check result will be determined by the fact who received it firstly. CarrierPrivilegesListener provides the reliable async API to get the CP status update notification. This CL also move CarrierPrivilegesUtils to cts common lib to make it available for other cts modules. Bug: 217559768 Test: atest ConnectivityDiagnosticsManagerTest VcnManagerTest Change-Id: I7c1b9ece117f0d8ad08cb32706bcd88d228c4af5 --- Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index f3703d9274..028c6b790b 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -59,12 +59,13 @@ import android.os.ParcelUuid; import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.cts.util.CarrierPrivilegeUtils; import android.telephony.cts.util.SubscriptionGroupUtils; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.compatibility.common.util.CarrierPrivilegeUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; From b5ccde0815efe21e8317b90b4746fc82133c5c5f Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 4 Feb 2022 17:35:19 -0800 Subject: [PATCH 0321/1057] Set foldable annotation for CtsVcnTestCases Annotate CtsIkeTestCases with no_foldable_state since this test module has no dependencies on foldable state. Bug: 197815249 Test: atest CtsVcnTestCases Change-Id: Icfbfafd69f367ba9ca646b43863dc2bc5530c78f --- Vcn/tests/cts/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/AndroidTest.xml b/Vcn/tests/cts/AndroidTest.xml index 519b88a43b..4b431b3257 100644 --- a/Vcn/tests/cts/AndroidTest.xml +++ b/Vcn/tests/cts/AndroidTest.xml @@ -19,6 +19,7 @@

      An app that has carrier privileges for any of the subscriptions in the given group may * clear a VCN configuration. This API is ONLY permitted for callers running as the primary - * user. Any active VCN will be torn down. + * user. Any active VCN associated with this configuration will be torn down. * * @param subscriptionGroup the subscription group that the configuration should be applied to - * @throws SecurityException if the caller does not have carrier privileges, or is not running - * as the primary user + * @throws SecurityException if the caller does not have carrier privileges, is not the owner of + * the associated configuration, or is not running as the primary user * @throws IOException if the configuration failed to be cleared from disk. This may occur due * to temporary disk errors, or more permanent conditions such as a full disk. */ @@ -196,8 +196,13 @@ public class VcnManager { /** * Retrieves the list of Subscription Groups for which a VCN Configuration has been set. * - *

      The returned list will include only subscription groups for which the carrier app is - * privileged, and which have an associated {@link VcnConfig}. + *

      The returned list will include only subscription groups for which an associated {@link + * VcnConfig} exists, and the app is either: + * + *

        + *
      • Carrier privileged for that subscription group, or + *
      • Is the provisioning package of the config + *
      * * @throws SecurityException if the caller is not running as the primary user */ diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 2d328d8b09..fa5e93729a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -87,6 +87,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -172,7 +173,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnNetworkProvider mNetworkProvider; @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; - @NonNull private final BroadcastReceiver mPkgChangeReceiver; + @NonNull private final BroadcastReceiver mVcnBroadcastReceiver; @NonNull private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback(); @@ -217,28 +218,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); - mPkgChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (Intent.ACTION_PACKAGE_ADDED.equals(action) - || Intent.ACTION_PACKAGE_REPLACED.equals(action) - || Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - mTelephonySubscriptionTracker.handleSubscriptionsChanged(); - } else { - Log.wtf(TAG, "received unexpected intent: " + action); - } - } - }; + mVcnBroadcastReceiver = new VcnBroadcastReceiver(); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver( - mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler); + mVcnBroadcastReceiver, intentFilter, null /* broadcastPermission */, mHandler); // Run on handler to ensure I/O does not block system server startup mHandler.post(() -> { @@ -443,6 +433,53 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); } + private class VcnBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + switch (action) { + case Intent.ACTION_PACKAGE_ADDED: // Fallthrough + case Intent.ACTION_PACKAGE_REPLACED: // Fallthrough + case Intent.ACTION_PACKAGE_REMOVED: + // Reevaluate subscriptions + mTelephonySubscriptionTracker.handleSubscriptionsChanged(); + + break; + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + final String pkgName = intent.getData().getSchemeSpecificPart(); + + if (pkgName == null || pkgName.isEmpty()) { + logWtf("Package name was empty or null for intent with action" + action); + return; + } + + // Clear configs for the packages that had data cleared, or removed. + synchronized (mLock) { + final List toRemove = new ArrayList<>(); + for (Entry entry : mConfigs.entrySet()) { + if (pkgName.equals(entry.getValue().getProvisioningPackageName())) { + toRemove.add(entry.getKey()); + } + } + + for (ParcelUuid subGrp : toRemove) { + stopAndClearVcnConfigInternalLocked(subGrp); + } + + if (!toRemove.isEmpty()) { + writeConfigsToDiskLocked(); + } + } + + break; + default: + Slog.wtf(TAG, "received unexpected intent: " + action); + } + } + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -504,6 +541,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Map> currSubGrpMappings = getSubGroupToSubIdMappings(mLastSnapshot); if (!currSubGrpMappings.equals(oldSubGrpMappings)) { + garbageCollectAndWriteVcnConfigsLocked(); notifyAllPolicyListenersLocked(); } } @@ -643,6 +681,39 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } + private void enforceCarrierPrivilegeOrProvisioningPackage( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Only apps running in the primary (system) user are allowed to configure the VCN. This is + // in line with Telephony's behavior with regards to binding to a Carrier App provided + // CarrierConfigService. + enforcePrimaryUser(); + + if (isProvisioningPackageForConfig(subscriptionGroup, pkg)) { + return; + } + + // Must NOT be called from cleared binder identity, since this checks user calling identity + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, pkg); + } + + private boolean isProvisioningPackageForConfig( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Try-finally to return early if matching owned subscription found. + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + final VcnConfig config = mConfigs.get(subscriptionGroup); + if (config != null && pkg.equals(config.getProvisioningPackageName())) { + return true; + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + + return false; + } + /** * Clears the VcnManagementService for a given subscription group. * @@ -656,31 +727,56 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); + enforceCarrierPrivilegeOrProvisioningPackage(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { - mConfigs.remove(subscriptionGroup); - final boolean vcnExists = mVcns.containsKey(subscriptionGroup); - - stopVcnLocked(subscriptionGroup); - - if (vcnExists) { - // TODO(b/181789060): invoke asynchronously after Vcn notifies through - // VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); - } - + stopAndClearVcnConfigInternalLocked(subscriptionGroup); writeConfigsToDiskLocked(); } }); } + private void stopAndClearVcnConfigInternalLocked(@NonNull ParcelUuid subscriptionGroup) { + mConfigs.remove(subscriptionGroup); + final boolean vcnExists = mVcns.containsKey(subscriptionGroup); + + stopVcnLocked(subscriptionGroup); + + if (vcnExists) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through + // VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); + } + } + + private void garbageCollectAndWriteVcnConfigsLocked() { + final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); + + boolean shouldWrite = false; + + final Iterator configsIterator = mConfigs.keySet().iterator(); + while (configsIterator.hasNext()) { + final ParcelUuid subGrp = configsIterator.next(); + + final List subscriptions = subMgr.getSubscriptionsInGroup(subGrp); + if (subscriptions == null || subscriptions.isEmpty()) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + configsIterator.remove(); + shouldWrite = true; + } + } + + if (shouldWrite) { + writeConfigsToDiskLocked(); + } + } + /** * Retrieves the list of subscription groups with configured VcnConfigs * - *

      Limited to subscription groups for which the caller is carrier privileged. + *

      Limited to subscription groups for which the caller had configured. * *

      Implements the IVcnManagementService Binder interface. */ @@ -696,7 +792,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { final List result = new ArrayList<>(); synchronized (mLock) { for (ParcelUuid subGrp : mConfigs.keySet()) { - if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) { + if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName) + || isProvisioningPackageForConfig(subGrp, opPkgName)) { result.add(subGrp); } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index bb98bc0bab..54b3c400af 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -65,6 +65,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -114,18 +115,24 @@ import java.util.UUID; public class VcnManagementServiceTest { private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); + private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2"; private static final String TEST_CB_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName() + ".callback"; private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); + private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2)); private static final VcnConfig TEST_VCN_CONFIG; + private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final int TEST_UID = Process.FIRST_APPLICATION_UID; static { final Context mockConfigContext = mock(Context.class); - doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); + doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext); + + doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName(); + TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext); } private static final Map TEST_VCN_CONFIG_MAP = @@ -246,18 +253,24 @@ public class VcnManagementServiceTest { eq(android.Manifest.permission.NETWORK_FACTORY), any()); } + private void setupMockedCarrierPrivilege(boolean isPrivileged) { + setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME); + } + + private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) .getSubscriptionsInGroup(any()); doReturn(mTelMgr) .when(mTelMgr) .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); - doReturn(isPrivileged - ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS - : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) + doReturn( + isPrivileged + ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) .when(mTelMgr) - .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME)); + .checkCarrierPrivilegesForPackage(eq(pkg)); } @Test @@ -414,7 +427,13 @@ public class VcnManagementServiceTest { private BroadcastReceiver getPackageChangeReceiver() { final ArgumentCaptor captor = ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any()); + verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) + && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED) + && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + }), any(), any()); return captor.getValue(); } @@ -538,6 +557,44 @@ public class VcnManagementServiceTest { verify(mSubscriptionTracker).handleSubscriptionsChanged(); } + @Test + public void testPackageChangeListener_packageDataCleared() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test + public void testPackageChangeListener_packageFullyRemoved() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -578,7 +635,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage"); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2); fail("Expected exception due to mismatched packages in config and method call"); } catch (IllegalArgumentException expected) { verify(mMockPolicyListener, never()).onPolicyChanged(); @@ -678,11 +735,12 @@ public class VcnManagementServiceTest { } @Test - public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception { + public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage() + throws Exception { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } @@ -691,19 +749,31 @@ public class VcnManagementServiceTest { @Test public void testClearVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage"); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } } @Test - public void testClearVcnConfig() throws Exception { + public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception { + // Lose carrier privileges to test that provisioning package is sufficient. + setupMockedCarrierPrivilege(false); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } + @Test + public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + @Test public void testClearVcnConfigNotifiesStatusCallback() throws Exception { setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */); @@ -755,11 +825,12 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception { - final String badPackage = "IncorrectPackage"; - doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage); + doThrow(new SecurityException()) + .when(mAppOpsMgr) + .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2); try { - mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage); + mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } @@ -767,14 +838,16 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroups() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2); - // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are - // privileged for. + // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are + // privileged for, or are the provisioning package of. triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); - assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); + assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps); } @Test From c6ae70d67e2d16c09f9fc5745e94d7bd8b21e57c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 13 Apr 2022 22:32:23 +0000 Subject: [PATCH 0332/1057] Update the constants to use Environment This change updates the file storage constants to use the Environment system data paths instead of redefined constants. Bug: 215406468 Test: atest FrameworksVcnTests Change-Id: If11c600601704b78527c3c1b48cc908e75f3d791 --- .../src/com/android/server/VcnManagementService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index eefeee3918..f26d9f9f49 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -52,6 +52,7 @@ import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.Binder; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -82,6 +83,7 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; +import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -162,7 +164,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { public static final boolean VDBG = false; // STOPSHIP: if true @VisibleForTesting(visibility = Visibility.PRIVATE) - static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; + static final String VCN_CONFIG_FILE = + new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath(); /* Binder context for this service */ @NonNull private final Context mContext; From 9162883fbc503056965147bec936e90c37429388 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 12 Apr 2022 16:40:37 -0700 Subject: [PATCH 0333/1057] Maximize VCN MTU when using IPv6 This commit maximizes VCN MTU by considering IP version. Specifically, VcnGateWayConnection stores/updates the IkeSessionConnectionInfo passed out from the IKE library during IKE setup and migration. By looking into the addresses stored in the IkeSessionConnectionInfo, VCN is able to know the IP family of the VCN tunnels. Bug: 222331693 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I9a2839d7827f1d6451546ec222129f286e94ae36 --- .../src/android/net/vcn/util/MtuUtils.java | 27 +++- .../server/vcn/VcnGatewayConnection.java | 117 +++++++++++++++--- ...cnGatewayConnectionConnectedStateTest.java | 15 ++- .../server/vcn/VcnGatewayConnectionTest.java | 6 +- .../vcn/VcnGatewayConnectionTestBase.java | 16 +++ .../android/server/vcn/util/MtuUtilsTest.java | 93 +++++++++++--- 6 files changed, 236 insertions(+), 38 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java index 5d40cca3e1..356c71f5f2 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java @@ -51,9 +51,20 @@ public class MtuUtils { /** * Max ESP overhead possible * - *

      60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader) + *

      60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next + * Header). Note: Payload data, Pad Length and Next Header will need to be padded to be multiple + * of the block size of a cipher, and at the same time be aligned on a 4-byte boundary. */ - private static final int GENERIC_ESP_OVERHEAD_MAX = 78; + private static final int GENERIC_ESP_OVERHEAD_MAX_V4 = 78; + + /** + * Max ESP overhead possible + * + *

      40 (Outer IPv6) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next Header). Note: Payload data, + * Pad Length and Next Header will need to be padded to be multiple of the block size of a + * cipher, and at the same time be aligned on a 4-byte boundary. + */ + private static final int GENERIC_ESP_OVERHEAD_MAX_V6 = 50; /** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */ private static final Map AUTH_ALGORITHM_OVERHEAD; @@ -108,7 +119,10 @@ public class MtuUtils { *

    */ public static int getMtu( - @NonNull List childProposals, int maxMtu, int underlyingMtu) { + @NonNull List childProposals, + int maxMtu, + int underlyingMtu, + boolean isIpv4) { if (underlyingMtu <= 0) { return IPV6_MIN_MTU; } @@ -145,10 +159,13 @@ public class MtuUtils { } } + final int genericEspOverheadMax = + isIpv4 ? GENERIC_ESP_OVERHEAD_MAX_V4 : GENERIC_ESP_OVERHEAD_MAX_V6; + // Return minimum of maxMtu, and the adjusted MTUs based on algorithms. - final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX; + final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - genericEspOverheadMax; final int normalModeMtu = - underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX; + underlyingMtu - maxCryptOverhead - maxAuthOverhead - genericEspOverheadMax; return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index cefd8efe96..05df22f124 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -61,6 +61,7 @@ import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; @@ -509,6 +510,42 @@ public class VcnGatewayConnection extends StateMachine { } } + /** + * Sent when an IKE session connection information has changed. + * + *

    This signal is always fired before EVENT_SETUP_COMPLETED and EVENT_MIGRATION_COMPLETED. + * + *

    Only relevant in the Connecting and Connected state. + * + * @param arg1 The session token for the IKE Session whose connection information has changed, + * used to prevent out-of-date signals from propagating. + * @param obj @NonNull An EventIkeConnectionInfoChangedInfo instance with relevant data. + */ + private static final int EVENT_IKE_CONNECTION_INFO_CHANGED = 12; + + private static class EventIkeConnectionInfoChangedInfo implements EventInfo { + @NonNull public final IkeSessionConnectionInfo ikeConnectionInfo; + + EventIkeConnectionInfoChangedInfo(@NonNull IkeSessionConnectionInfo ikeConnectionInfo) { + this.ikeConnectionInfo = ikeConnectionInfo; + } + + @Override + public int hashCode() { + return Objects.hash(ikeConnectionInfo); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventIkeConnectionInfoChangedInfo)) { + return false; + } + + final EventIkeConnectionInfoChangedInfo rhs = (EventIkeConnectionInfoChangedInfo) other; + return Objects.equals(ikeConnectionInfo, rhs.ikeConnectionInfo); + } + } + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -623,6 +660,14 @@ public class VcnGatewayConnection extends StateMachine { */ private UnderlyingNetworkRecord mUnderlying; + /** + * The current IKE Session connection information + * + *

    Set in Connected and Migrating states, always @NonNull in Connected, Migrating + * states, @Nullable otherwise. + */ + private IkeSessionConnectionInfo mIkeConnectionInfo; + /** * The active IKE session. * @@ -1197,6 +1242,14 @@ public class VcnGatewayConnection extends StateMachine { exceptionMessage); } + private void ikeConnectionInfoChanged( + int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { + sendMessageAndAcquireWakeLock( + EVENT_IKE_CONNECTION_INFO_CHANGED, + token, + new EventIkeConnectionInfoChangedInfo(ikeConnectionInfo)); + } + private void sessionClosed(int token, @Nullable Exception exception) { if (exception != null) { notifyStatusCallbackForSessionClosed(exception); @@ -1313,7 +1366,8 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough - case EVENT_MIGRATION_COMPLETED: + case EVENT_MIGRATION_COMPLETED: // Fallthrough + case EVENT_IKE_CONNECTION_INFO_CHANGED: logUnexpectedEvent(msg.what); break; default: @@ -1592,6 +1646,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mDisconnectingState); break; case EVENT_SETUP_COMPLETED: // fallthrough + case EVENT_IKE_CONNECTION_INFO_CHANGED: // fallthrough case EVENT_TRANSFORM_CREATED: // Child setup complete; move to ConnectedState for NetworkAgent registration deferMessage(msg); @@ -1614,12 +1669,17 @@ public class VcnGatewayConnection extends StateMachine { protected void updateNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnNetworkAgent agent, - @NonNull VcnChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( - mConnectionConfig, tunnelIface, childConfig, mUnderlying); + mConnectionConfig, + tunnelIface, + childConfig, + mUnderlying, + ikeConnectionInfo); agent.sendNetworkCapabilities(caps); agent.sendLinkProperties(lp); @@ -1630,12 +1690,17 @@ public class VcnGatewayConnection extends StateMachine { protected VcnNetworkAgent buildNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, - @NonNull VcnChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( - mConnectionConfig, tunnelIface, childConfig, mUnderlying); + mConnectionConfig, + tunnelIface, + childConfig, + mUnderlying, + ikeConnectionInfo); final NetworkAgentConfig nac = new NetworkAgentConfig.Builder() .setLegacyType(ConnectivityManager.TYPE_MOBILE) @@ -1838,7 +1903,11 @@ public class VcnGatewayConnection extends StateMachine { mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig; setupInterfaceAndNetworkAgent( - mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig); + mCurrentToken, + mTunnelIface, + mChildConfig, + oldChildConfig, + mIkeConnectionInfo); break; case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); @@ -1852,6 +1921,10 @@ public class VcnGatewayConnection extends StateMachine { handleMigrationCompleted(migrationCompletedInfo); break; + case EVENT_IKE_CONNECTION_INFO_CHANGED: + mIkeConnectionInfo = + ((EventIkeConnectionInfoChangedInfo) msg.obj).ikeConnectionInfo; + break; default: logUnhandledMessage(msg); break; @@ -1875,7 +1948,7 @@ public class VcnGatewayConnection extends StateMachine { migrationCompletedInfo.outTransform, IpSecManager.DIRECTION_OUT); - updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo); // Trigger re-validation after migration events. mConnectivityManager.reportNetworkConnectivity( @@ -1906,7 +1979,8 @@ public class VcnGatewayConnection extends StateMachine { // Network not yet set up, or child not yet connected. if (mNetworkAgent != null && mChildConfig != null) { // If only network properties changed and agent is active, update properties - updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + updateNetworkAgent( + mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo); } } } @@ -1915,13 +1989,14 @@ public class VcnGatewayConnection extends StateMachine { int token, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, - @NonNull VcnChildSessionConfiguration oldChildConfig) { + @NonNull VcnChildSessionConfiguration oldChildConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { setupInterface(token, tunnelIface, childConfig, oldChildConfig); if (mNetworkAgent == null) { - mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig); + mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig, ikeConnectionInfo); } else { - updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig); + updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig, ikeConnectionInfo); // mNetworkAgent not null, so the VCN Network has already been established. Clear // the failed attempt counter and safe mode alarm since this transition is complete. @@ -2098,7 +2173,8 @@ public class VcnGatewayConnection extends StateMachine { @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, - @Nullable UnderlyingNetworkRecord underlying) { + @Nullable UnderlyingNetworkRecord underlying, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final IkeTunnelConnectionParams ikeTunnelParams = gatewayConnectionConfig.getTunnelConnectionParams(); final LinkProperties lp = new LinkProperties(); @@ -2139,7 +2215,8 @@ public class VcnGatewayConnection extends StateMachine { MtuUtils.getMtu( ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), gatewayConnectionConfig.getMaxMtu(), - underlyingMtu)); + underlyingMtu, + ikeConnectionInfo.getLocalAddress() instanceof Inet4Address)); return lp; } @@ -2154,7 +2231,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { logDbg("IkeOpened for token " + mToken); - // Nothing to do here. + ikeConnectionInfoChanged(mToken, ikeSessionConfig.getIkeSessionConnectionInfo()); } @Override @@ -2174,6 +2251,13 @@ public class VcnGatewayConnection extends StateMachine { logInfo("IkeError for token " + mToken, exception); // Non-fatal, log and continue. } + + @Override + public void onIkeSessionConnectionInfoChanged( + @NonNull IkeSessionConnectionInfo connectionInfo) { + logDbg("onIkeSessionConnectionInfoChanged for token " + mToken); + ikeConnectionInfoChanged(mToken, connectionInfo); + } } /** Implementation of ChildSessionCallback, exposed for testing. */ @@ -2349,6 +2433,11 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = record; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + IkeSessionConnectionInfo getIkeConnectionInfo() { + return mIkeConnectionInfo; + } + @VisibleForTesting(visibility = Visibility.PRIVATE) boolean isQuitting() { return mIsQuitting.getValue(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 841b81c2a2..15d4f10971 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -56,6 +56,7 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -216,14 +217,23 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testMigration() throws Exception { triggerChildOpened(); + mTestLooper.dispatchAll(); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); mGatewayConnection .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + + final IkeSessionConnectionInfo newIkeConnectionInfo = + new IkeSessionConnectionInfo( + TEST_ADDR_V4, TEST_ADDR_V4_2, TEST_UNDERLYING_NETWORK_RECORD_2.network); + getIkeSessionCallback().onIkeSessionConnectionInfoChanged(newIkeConnectionInfo); getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); + assertEquals(newIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); + verify(mIpSecSvc, times(2)) .setNetworkForTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), @@ -246,7 +256,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection MtuUtils.getMtu( saProposals, mConfig.getMaxMtu(), - TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu()); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu(), + true /* isIpv4 */); verify(mNetworkAgent).sendLinkProperties( argThat(lp -> expectedMtu == lp.getMtu() && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); @@ -269,6 +280,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .when(mMockChildSessionConfig) .getInternalDnsServers(); + getIkeSessionCallback().onOpened(mIkeSessionConfiguration); getChildSessionCallback().onOpened(mMockChildSessionConfig); } @@ -298,6 +310,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); final ArgumentCaptor lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index b9dfda38a0..6a9a1e22ca 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -213,7 +213,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { VcnGatewayConnectionConfigTest.buildTestConfig(), tunnelIface, childSessionConfig, - record); + record, + mIkeConnectionInfo); verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); @@ -226,7 +227,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { VcnGatewayConnectionConfigTest.buildTestConfig(), tunnelIface, childSessionConfig, - record); + record, + mIkeConnectionInfo); verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 5628321b59..3d95a9b32d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -47,6 +47,8 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; @@ -80,6 +82,13 @@ public class VcnGatewayConnectionTestBase { doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid(); } + protected static final InetAddress TEST_ADDR = InetAddresses.parseNumericAddress("2001:db8::1"); + protected static final InetAddress TEST_ADDR_2 = + InetAddresses.parseNumericAddress("2001:db8::2"); + protected static final InetAddress TEST_ADDR_V4 = + InetAddresses.parseNumericAddress("192.0.2.1"); + protected static final InetAddress TEST_ADDR_V4_2 = + InetAddresses.parseNumericAddress("192.0.2.2"); protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); protected static final InetAddress TEST_DNS_ADDR_2 = @@ -148,6 +157,9 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; + @NonNull protected final IkeSessionConnectionInfo mIkeConnectionInfo; + @NonNull protected final IkeSessionConfiguration mIkeSessionConfiguration; + protected VcnIkeSession mMockIkeSession; protected VcnGatewayConnection mGatewayConnection; @@ -173,6 +185,10 @@ public class VcnGatewayConnectionTestBase { VcnTestUtils.setupSystemService( mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + mIkeConnectionInfo = + new IkeSessionConnectionInfo(TEST_ADDR, TEST_ADDR_2, mock(Network.class)); + mIkeSessionConfiguration = new IkeSessionConfiguration.Builder(mIkeConnectionInfo).build(); + doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java index 29511f780b..e9e70783eb 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java @@ -46,34 +46,85 @@ import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class MtuUtilsTest { - @Test - public void testUnderlyingMtuZero() { + private void verifyUnderlyingMtuZero(boolean isIpv4) { assertEquals( - IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */)); + IPV6_MIN_MTU, + getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */, isIpv4)); } @Test - public void testClampsToMaxMtu() { - assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */)); + public void testUnderlyingMtuZeroV4() { + verifyUnderlyingMtuZero(true /* isIpv4 */); } @Test - public void testNormalModeAlgorithmLessThanUnderlyingMtu() { - final List saProposals = - Arrays.asList( - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256) - .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) - .build()); + public void testUnderlyingMtuZeroV6() { + verifyUnderlyingMtuZero(false /* isIpv4 */); + } + private void verifyClampsToMaxMtu(boolean isIpv4) { + assertEquals( + 0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */, isIpv4)); + } + + @Test + public void testClampsToMaxMtuV4() { + verifyClampsToMaxMtu(true /* isIpv4 */); + } + + @Test + public void testClampsToMaxMtuV6() { + verifyClampsToMaxMtu(false /* isIpv4 */); + } + + private List buildChildSaProposalsWithNormalModeAlgo() { + return Arrays.asList( + new ChildSaProposal.Builder() + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .build()); + } + + private void verifyNormalModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) { final int actualMtu = - getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + isIpv4); assertTrue(ETHER_MTU > actualMtu); } @Test - public void testCombinedModeAlgorithmLessThanUnderlyingMtu() { + public void testNormalModeAlgorithmLessThanUnderlyingMtuV4() { + verifyNormalModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */); + } + + @Test + public void testNormalModeAlgorithmLessThanUnderlyingMtuV6() { + verifyNormalModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */); + } + + @Test + public void testMtuIpv4LessThanMtuIpv6() { + final int actualMtuV4 = + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + true /* isIpv4 */); + + final int actualMtuV6 = + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + false /* isIpv4 */); + + assertTrue(actualMtuV4 < actualMtuV6); + } + + private void verifyCombinedModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) { final List saProposals = Arrays.asList( new ChildSaProposal.Builder() @@ -86,7 +137,17 @@ public class MtuUtilsTest { .build()); final int actualMtu = - getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */, isIpv4); assertTrue(ETHER_MTU > actualMtu); } + + @Test + public void testCombinedModeAlgorithmLessThanUnderlyingMtuV4() { + verifyCombinedModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */); + } + + @Test + public void testCombinedModeAlgorithmLessThanUnderlyingMtuV6() { + verifyCombinedModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */); + } } From 276011c4d2741dd73fb61c4c1c30d2ba361d9bd9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 13 Apr 2022 01:54:32 +0000 Subject: [PATCH 0334/1057] Add CarrierConfig to TelephonySubscriptionSnapshot This change ensures that carrier configs are saved as part of the snapshot, allowing all entities in the VCN to query telephony subscription information from the same source. Test: atest FrameworksVcnTests Change-Id: I31447d84fe98d6bd2cc78ead41746198728c400b --- .../src/android/net/vcn/VcnManager.java | 8 + .../net/vcn/util/PersistableBundleUtils.java | 180 ++++++++++++++++++ .../vcn/TelephonySubscriptionTracker.java | 86 ++++++++- .../NetworkPriorityClassifier.java | 14 +- .../UnderlyingNetworkController.java | 30 +-- .../UnderlyingNetworkRecord.java | 9 +- .../vcn/TelephonySubscriptionTrackerTest.java | 57 +++++- .../vcn/VcnGatewayConnectionTestBase.java | 1 + .../NetworkPriorityClassifierTest.java | 5 +- .../vcn/util/PersistableBundleUtilsTest.java | 82 ++++++++ 10 files changed, 425 insertions(+), 47 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index f1b110ab29..40e4083c02 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -104,6 +104,14 @@ public class VcnManager { // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz + /** List of Carrier Config options to extract from Carrier Config bundles. @hide */ + @NonNull + public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS = + new String[] { + VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY + }; + private static final Map< VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 1c675c2285..08e8eebb87 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -28,11 +28,13 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.TreeSet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -354,4 +356,182 @@ public class PersistableBundleUtils { } } } + + /** + * Returns a copy of the persistable bundle with only the specified keys + * + *

    This allows for holding minimized copies for memory-saving purposes. + */ + @NonNull + public static PersistableBundle minimizeBundle( + @NonNull PersistableBundle bundle, String... keys) { + final PersistableBundle minimized = new PersistableBundle(); + + if (bundle == null) { + return minimized; + } + + for (String key : keys) { + if (bundle.containsKey(key)) { + final Object value = bundle.get(key); + if (value == null) { + continue; + } + + if (value instanceof Boolean) { + minimized.putBoolean(key, (Boolean) value); + } else if (value instanceof boolean[]) { + minimized.putBooleanArray(key, (boolean[]) value); + } else if (value instanceof Double) { + minimized.putDouble(key, (Double) value); + } else if (value instanceof double[]) { + minimized.putDoubleArray(key, (double[]) value); + } else if (value instanceof Integer) { + minimized.putInt(key, (Integer) value); + } else if (value instanceof int[]) { + minimized.putIntArray(key, (int[]) value); + } else if (value instanceof Long) { + minimized.putLong(key, (Long) value); + } else if (value instanceof long[]) { + minimized.putLongArray(key, (long[]) value); + } else if (value instanceof String) { + minimized.putString(key, (String) value); + } else if (value instanceof String[]) { + minimized.putStringArray(key, (String[]) value); + } else if (value instanceof PersistableBundle) { + minimized.putPersistableBundle(key, (PersistableBundle) value); + } else { + continue; + } + } + } + + return minimized; + } + + /** Builds a stable hashcode */ + public static int getHashCode(@Nullable PersistableBundle bundle) { + if (bundle == null) { + return -1; + } + + int iterativeHashcode = 0; + TreeSet treeSet = new TreeSet<>(bundle.keySet()); + for (String key : treeSet) { + Object val = bundle.get(key); + if (val instanceof PersistableBundle) { + iterativeHashcode = + Objects.hash(iterativeHashcode, key, getHashCode((PersistableBundle) val)); + } else { + iterativeHashcode = Objects.hash(iterativeHashcode, key, val); + } + } + + return iterativeHashcode; + } + + /** Checks for persistable bundle equality */ + public static boolean isEqual( + @Nullable PersistableBundle left, @Nullable PersistableBundle right) { + // Check for pointer equality & null equality + if (Objects.equals(left, right)) { + return true; + } + + // If only one of the two is null, but not the other, not equal by definition. + if (Objects.isNull(left) != Objects.isNull(right)) { + return false; + } + + if (!left.keySet().equals(right.keySet())) { + return false; + } + + for (String key : left.keySet()) { + Object leftVal = left.get(key); + Object rightVal = right.get(key); + + // Check for equality + if (Objects.equals(leftVal, rightVal)) { + continue; + } else if (Objects.isNull(leftVal) != Objects.isNull(rightVal)) { + // If only one of the two is null, but not the other, not equal by definition. + return false; + } else if (!Objects.equals(leftVal.getClass(), rightVal.getClass())) { + // If classes are different, not equal by definition. + return false; + } + if (leftVal instanceof PersistableBundle) { + if (!isEqual((PersistableBundle) leftVal, (PersistableBundle) rightVal)) { + return false; + } + } else if (leftVal.getClass().isArray()) { + if (leftVal instanceof boolean[]) { + if (!Arrays.equals((boolean[]) leftVal, (boolean[]) rightVal)) { + return false; + } + } else if (leftVal instanceof double[]) { + if (!Arrays.equals((double[]) leftVal, (double[]) rightVal)) { + return false; + } + } else if (leftVal instanceof int[]) { + if (!Arrays.equals((int[]) leftVal, (int[]) rightVal)) { + return false; + } + } else if (leftVal instanceof long[]) { + if (!Arrays.equals((long[]) leftVal, (long[]) rightVal)) { + return false; + } + } else if (!Arrays.equals((Object[]) leftVal, (Object[]) rightVal)) { + return false; + } + } else { + if (!Objects.equals(leftVal, rightVal)) { + return false; + } + } + } + + return true; + } + + /** + * Wrapper class around PersistableBundles to allow equality comparisons + * + *

    This class exposes the minimal getters to retrieve values. + */ + public static class PersistableBundleWrapper { + @NonNull private final PersistableBundle mBundle; + + public PersistableBundleWrapper(@NonNull PersistableBundle bundle) { + mBundle = Objects.requireNonNull(bundle, "Bundle was null"); + } + + /** + * Retrieves the integer associated with the provided key. + * + * @param key the string key to query + * @param defaultValue the value to return if key does not exist + * @return the int value, or the default + */ + public int getInt(String key, int defaultValue) { + return mBundle.getInt(key, defaultValue); + } + + @Override + public int hashCode() { + return getHashCode(mBundle); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof PersistableBundleWrapper)) { + return false; + } + + final PersistableBundleWrapper other = (PersistableBundleWrapper) obj; + + return isEqual(mBundle, other.mBundle); + } + } } diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 89470ec00a..5c305c6902 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -29,6 +29,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.vcn.VcnManager; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; @@ -47,6 +48,8 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.vcn.util.PersistableBundleUtils; +import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.util.ArrayList; import java.util.Collections; @@ -95,6 +98,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { // TODO (Android T+): Add ability to handle multiple subIds per slot. @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); + + @NonNull + private final Map mSubIdToCarrierConfigMap = new HashMap<>(); + @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @NonNull @@ -250,7 +257,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot newSnapshot = new TelephonySubscriptionSnapshot( - mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages); + mDeps.getActiveDataSubscriptionId(), + newSubIdToInfoMap, + mSubIdToCarrierConfigMap, + privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -311,47 +321,77 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } if (SubscriptionManager.isValidSubscriptionId(subId)) { - final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); - if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) { + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) { mReadySubIdsBySlotId.put(slotId, subId); + + final PersistableBundle minimized = + PersistableBundleUtils.minimizeBundle( + carrierConfig, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); + if (minimized != null) { + mSubIdToCarrierConfigMap.put(subId, new PersistableBundleWrapper(minimized)); + } handleSubscriptionsChanged(); } } else { - mReadySubIdsBySlotId.remove(slotId); + final Integer oldSubid = mReadySubIdsBySlotId.remove(slotId); + if (oldSubid != null) { + mSubIdToCarrierConfigMap.remove(oldSubid); + } handleSubscriptionsChanged(); } } @VisibleForTesting(visibility = Visibility.PRIVATE) void setReadySubIdsBySlotId(Map readySubIdsBySlotId) { + mReadySubIdsBySlotId.clear(); mReadySubIdsBySlotId.putAll(readySubIdsBySlotId); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setSubIdToCarrierConfigMap( + Map subIdToCarrierConfigMap) { + mSubIdToCarrierConfigMap.clear(); + mSubIdToCarrierConfigMap.putAll(subIdToCarrierConfigMap); + } + @VisibleForTesting(visibility = Visibility.PRIVATE) Map getReadySubIdsBySlotId() { return Collections.unmodifiableMap(mReadySubIdsBySlotId); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + Map getSubIdToCarrierConfigMap() { + return Collections.unmodifiableMap(mSubIdToCarrierConfigMap); + } + /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { private final int mActiveDataSubId; private final Map mSubIdToInfoMap; + private final Map mSubIdToCarrierConfigMap; private final Map> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = new TelephonySubscriptionSnapshot( - INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap()); + INVALID_SUBSCRIPTION_ID, + Collections.emptyMap(), + Collections.emptyMap(), + Collections.emptyMap()); @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( int activeDataSubId, @NonNull Map subIdToInfoMap, + @NonNull Map subIdToCarrierConfigMap, @NonNull Map> privilegedPackages) { mActiveDataSubId = activeDataSubId; Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); + Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null"); mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap); + mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap); final Map> unmodifiableInnerSets = new ArrayMap<>(); for (Entry> entry : privilegedPackages.entrySet()) { @@ -423,9 +463,40 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { : false; } + /** + * Retrieves a carrier config for a subscription in the provided group. + * + *

    This method will prioritize non-opportunistic subscriptions, but will use the a + * carrier config for an opportunistic subscription if no other subscriptions are found. + */ + @Nullable + public PersistableBundleWrapper getCarrierConfigForSubGrp(@NonNull ParcelUuid subGrp) { + PersistableBundleWrapper result = null; + + for (int subId : getAllSubIdsInGroup(subGrp)) { + final PersistableBundleWrapper config = mSubIdToCarrierConfigMap.get(subId); + if (config != null) { + result = config; + + // Attempt to use (any) non-opportunistic subscription. If this subscription is + // opportunistic, continue and try to find a non-opportunistic subscription, + // using the opportunistic ones as a last resort. + if (!isOpportunistic(subId)) { + return config; + } + } + } + + return result; + } + @Override public int hashCode() { - return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages); + return Objects.hash( + mActiveDataSubId, + mSubIdToInfoMap, + mSubIdToCarrierConfigMap, + mPrivilegedPackages); } @Override @@ -438,6 +509,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return mActiveDataSubId == other.mActiveDataSubId && mSubIdToInfoMap.equals(other.mSubIdToInfoMap) + && mSubIdToCarrierConfigMap.equals(other.mSubIdToCarrierConfigMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -448,6 +520,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("mActiveDataSubId: " + mActiveDataSubId); pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); + pw.println("mSubIdToCarrierConfigMap: " + mSubIdToCarrierConfigMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); pw.decreaseIndent(); @@ -458,6 +531,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return "TelephonySubscriptionSnapshot{ " + "mActiveDataSubId=" + mActiveDataSubId + ", mSubIdToInfoMap=" + mSubIdToInfoMap + + ", mSubIdToCarrierConfigMap=" + mSubIdToCarrierConfigMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index c96c1ee01a..2f84fddc72 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static com.android.server.VcnManagementService.LOCAL_LOG; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -34,7 +35,6 @@ import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.os.ParcelUuid; -import android.os.PersistableBundle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Slog; @@ -81,7 +81,7 @@ class NetworkPriorityClassifier { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED if (networkRecord.isBlocked) { @@ -119,7 +119,7 @@ class NetworkPriorityClassifier { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; final boolean isSelectedUnderlyingNetwork = currentlySelected != null @@ -181,7 +181,7 @@ class NetworkPriorityClassifier { VcnWifiUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; if (!caps.hasTransport(TRANSPORT_WIFI)) { @@ -204,7 +204,7 @@ class NetworkPriorityClassifier { private static boolean isWifiRssiAcceptable( UnderlyingNetworkRecord networkRecord, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; final boolean isSelectedNetwork = currentlySelected != null @@ -314,7 +314,7 @@ class NetworkPriorityClassifier { return false; } - static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { + static int getWifiEntryRssiThreshold(@Nullable PersistableBundleWrapper carrierConfig) { if (carrierConfig != null) { return carrierConfig.getInt( VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, @@ -323,7 +323,7 @@ class NetworkPriorityClassifier { return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; } - static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { + static int getWifiExitRssiThreshold(@Nullable PersistableBundleWrapper carrierConfig) { if (carrierConfig != null) { return carrierConfig.getInt( VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index a3babf7c9f..d474c5d33a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -21,7 +21,7 @@ import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListen import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold; -import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.isOpportunistic; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -37,8 +37,6 @@ import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -51,7 +49,6 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -87,7 +84,7 @@ public class UnderlyingNetworkController { @Nullable private UnderlyingNetworkListener mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; - @Nullable private PersistableBundle mCarrierConfig; + @Nullable private PersistableBundleWrapper mCarrierConfig; private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @@ -124,25 +121,7 @@ public class UnderlyingNetworkController { .getSystemService(TelephonyManager.class) .registerTelephonyCallback(new HandlerExecutor(mHandler), mActiveDataSubIdListener); - // TODO: Listen for changes in carrier config that affect this. - for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - PersistableBundle config = - mVcnContext - .getContext() - .getSystemService(CarrierConfigManager.class) - .getConfigForSubId(subId); - - if (config != null) { - mCarrierConfig = config; - - // Attempt to use (any) non-opportunistic subscription. If this subscription is - // opportunistic, continue and try to find a non-opportunistic subscription, using - // the opportunistic ones as a last resort. - if (!isOpportunistic(mLastSnapshot, Collections.singleton(subId))) { - break; - } - } - } + mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup); registerOrUpdateNetworkRequests(); } @@ -334,6 +313,9 @@ public class UnderlyingNetworkController { final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = newSnapshot; + // Update carrier config + mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup); + // Only trigger re-registration if subIds in this group have changed if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index 06f92805ad..319680e0b0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -16,6 +16,8 @@ package com.android.server.vcn.routeselection; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.LinkProperties; @@ -23,7 +25,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.ParcelUuid; -import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -68,7 +69,7 @@ public class UnderlyingNetworkRecord { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { // Never changes after the underlying network record is created. if (mPriorityClass == PRIORITY_CLASS_INVALID) { mPriorityClass = @@ -113,7 +114,7 @@ public class UnderlyingNetworkRecord { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { return (left, right) -> { final int leftIndex = left.getOrCalculatePriorityClass( @@ -167,7 +168,7 @@ public class UnderlyingNetworkRecord { ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, - PersistableBundle carrierConfig) { + PersistableBundleWrapper carrierConfig) { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 5f606e1dab..09080be9ee 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -26,6 +26,7 @@ import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -50,9 +51,11 @@ import android.annotation.NonNull; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.vcn.VcnManager; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.test.TestLooper; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; @@ -104,6 +107,26 @@ public class TelephonySubscriptionTrackerTest { TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap); } + private static final String TEST_CARRIER_CONFIG_KEY_1 = "TEST_CARRIER_CONFIG_KEY_1"; + private static final String TEST_CARRIER_CONFIG_KEY_2 = "TEST_CARRIER_CONFIG_KEY_2"; + private static final PersistableBundle TEST_CARRIER_CONFIG = new PersistableBundle(); + private static final PersistableBundleWrapper TEST_CARRIER_CONFIG_WRAPPER; + private static final Map TEST_SUBID_TO_CARRIER_CONFIG_MAP; + + static { + TEST_CARRIER_CONFIG.putString( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY); + TEST_CARRIER_CONFIG.putString( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY); + TEST_CARRIER_CONFIG_WRAPPER = new PersistableBundleWrapper(TEST_CARRIER_CONFIG); + + final Map subIdToCarrierConfigMap = new HashMap<>(); + subIdToCarrierConfigMap.put(TEST_SUBSCRIPTION_ID_1, TEST_CARRIER_CONFIG_WRAPPER); + TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap); + } + @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; @NonNull private final Handler mHandler; @@ -144,6 +167,9 @@ public class TelephonySubscriptionTrackerTest { doReturn(mCarrierConfigManager) .when(mContext) .getSystemService(Context.CARRIER_CONFIG_SERVICE); + doReturn(TEST_CARRIER_CONFIG) + .when(mCarrierConfigManager) + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); // subId 1, 2 are in same subGrp, only subId 1 is active doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid(); @@ -227,14 +253,24 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map subIdToInfoMap, Map> privilegedPackages) { - return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages); + return buildExpectedSnapshot(0, subIdToInfoMap, privilegedPackages); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( int activeSubId, Map subIdToInfoMap, Map> privilegedPackages) { - return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages); + return buildExpectedSnapshot( + activeSubId, subIdToInfoMap, TEST_SUBID_TO_CARRIER_CONFIG_MAP, privilegedPackages); + } + + private TelephonySubscriptionSnapshot buildExpectedSnapshot( + int activeSubId, + Map subIdToInfoMap, + Map subIdToCarrierConfigMap, + Map> privilegedPackages) { + return new TelephonySubscriptionSnapshot( + activeSubId, subIdToInfoMap, subIdToCarrierConfigMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -245,6 +281,8 @@ public class TelephonySubscriptionTrackerTest { private void setupReadySubIds() { mTelephonySubscriptionTracker.setReadySubIdsBySlotId( Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1)); + mTelephonySubscriptionTracker.setSubIdToCarrierConfigMap( + Collections.singletonMap(TEST_SUBSCRIPTION_ID_1, TEST_CARRIER_CONFIG_WRAPPER)); } private void setPrivilegedPackagesForMock(@NonNull List privilegedPackages) { @@ -300,6 +338,7 @@ public class TelephonySubscriptionTrackerTest { readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX + 1, TEST_SUBSCRIPTION_ID_1); mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId); + mTelephonySubscriptionTracker.setSubIdToCarrierConfigMap(TEST_SUBID_TO_CARRIER_CONFIG_MAP); doReturn(1).when(mTelephonyManager).getActiveModemCount(); List carrierPrivilegesCallbacks = @@ -464,8 +503,16 @@ public class TelephonySubscriptionTrackerTest { mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); mTestLooper.dispatchAll(); - verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap()))); + verify(mCallback) + .onNewSnapshot( + eq( + buildExpectedSnapshot( + 0, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap()))); assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); + assertNull( + mTelephonySubscriptionTracker + .getSubIdToCarrierConfigMap() + .get(TEST_SUBSCRIPTION_ID_1)); } @Test @@ -493,7 +540,7 @@ public class TelephonySubscriptionTrackerTest { public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = new TelephonySubscriptionSnapshot( - TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -503,7 +550,7 @@ public class TelephonySubscriptionTrackerTest { public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = new TelephonySubscriptionSnapshot( - TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap()); + TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 5628321b59..4d25684438 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -129,6 +129,7 @@ public class VcnGatewayConnectionTestBase { new TelephonySubscriptionSnapshot( TEST_SUB_ID, Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), + Collections.EMPTY_MAP, Collections.EMPTY_MAP); @NonNull protected final Context mContext; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 6c849b5af8..b0d68952c3 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -30,6 +30,7 @@ import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.ch import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -309,7 +310,9 @@ public class NetworkPriorityClassifierTest { wifiNetworkPriority, mWifiNetworkRecord, selectedNetworkRecord, - carrierConfig)); + carrierConfig == null + ? null + : new PersistableBundleWrapper(carrierConfig))); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index a44a734a2d..294f5c1f48 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -18,6 +18,8 @@ package com.android.server.vcn.util; 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.os.PersistableBundle; @@ -211,4 +213,84 @@ public class PersistableBundleUtilsTest { assertEquals(testInt, result); } + + private PersistableBundle getTestBundle() { + final PersistableBundle bundle = new PersistableBundle(); + + bundle.putBoolean(TEST_KEY + "Boolean", true); + bundle.putBooleanArray(TEST_KEY + "BooleanArray", new boolean[] {true, false}); + bundle.putDouble(TEST_KEY + "Double", 0.1); + bundle.putDoubleArray(TEST_KEY + "DoubleArray", new double[] {0.1, 0.2, 0.3}); + bundle.putInt(TEST_KEY + "Int", 1); + bundle.putIntArray(TEST_KEY + "IntArray", new int[] {1, 2}); + bundle.putLong(TEST_KEY + "Long", 5L); + bundle.putLongArray(TEST_KEY + "LongArray", new long[] {0L, -1L, -2L}); + bundle.putString(TEST_KEY + "String", "TEST"); + bundle.putStringArray(TEST_KEY + "StringArray", new String[] {"foo", "bar", "bas"}); + bundle.putPersistableBundle( + TEST_KEY + "PersistableBundle", + new TestClass(1, TEST_INT_ARRAY, TEST_STRING_PREFIX, new PersistableBundle()) + .toPersistableBundle()); + + return bundle; + } + + @Test + public void testMinimizeBundle() throws Exception { + final String[] minimizedKeys = + new String[] { + TEST_KEY + "Boolean", + TEST_KEY + "BooleanArray", + TEST_KEY + "Double", + TEST_KEY + "DoubleArray", + TEST_KEY + "Int", + TEST_KEY + "IntArray", + TEST_KEY + "Long", + TEST_KEY + "LongArray", + TEST_KEY + "String", + TEST_KEY + "StringArray", + TEST_KEY + "PersistableBundle" + }; + + final PersistableBundle testBundle = getTestBundle(); + testBundle.putBoolean(TEST_KEY + "Boolean2", true); + + final PersistableBundle minimized = + PersistableBundleUtils.minimizeBundle(testBundle, minimizedKeys); + + // Verify that the minimized bundle is NOT the same in size OR values due to the extra + // Boolean2 key + assertFalse(PersistableBundleUtils.isEqual(testBundle, minimized)); + + // Verify that removing the extra key from the source bundle results in equality. + testBundle.remove(TEST_KEY + "Boolean2"); + assertTrue(PersistableBundleUtils.isEqual(testBundle, minimized)); + } + + @Test + public void testEquality_identical() throws Exception { + final PersistableBundle left = getTestBundle(); + final PersistableBundle right = getTestBundle(); + + assertTrue(PersistableBundleUtils.isEqual(left, right)); + } + + @Test + public void testEquality_different() throws Exception { + final PersistableBundle left = getTestBundle(); + final PersistableBundle right = getTestBundle(); + + left.putBoolean(TEST_KEY + "Boolean2", true); + assertFalse(PersistableBundleUtils.isEqual(left, right)); + + left.remove(TEST_KEY + "Boolean2"); + assertTrue(PersistableBundleUtils.isEqual(left, right)); + } + + @Test + public void testEquality_null() throws Exception { + assertFalse(PersistableBundleUtils.isEqual(getTestBundle(), null)); + assertFalse(PersistableBundleUtils.isEqual(null, getTestBundle())); + assertTrue(PersistableBundleUtils.isEqual(null, null)); + } } From 2d7894c1f15d13f634a922b64767cecc6ebdf9c5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 3 May 2022 04:29:38 +0000 Subject: [PATCH 0335/1057] Add to/from disk stable format This change adds a utility to convert persistable bundles to and from disk-stable byte arrays. Test: atest FrameworksVcnTests:PersistableBundleUtilsTest Change-Id: Ifafb7081ec6a34ce3ab8e2aa502d46411405cb6d --- .../net/vcn/util/PersistableBundleUtils.java | 26 +++++++++++++++++++ .../vcn/util/PersistableBundleUtilsTest.java | 9 +++++++ 2 files changed, 35 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 08e8eebb87..999d4064c9 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -23,6 +23,8 @@ import android.os.PersistableBundle; import com.android.internal.util.HexDump; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -295,6 +297,30 @@ public class PersistableBundleUtils { return result; } + /** + * Converts a PersistableBundle into a disk-stable byte array format + * + * @param bundle the PersistableBundle to be converted to a disk-stable format + * @return the byte array representation of the PersistableBundle + */ + @Nullable + public static byte[] toDiskStableBytes(@NonNull PersistableBundle bundle) throws IOException { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bundle.writeToStream(outputStream); + return outputStream.toByteArray(); + } + + /** + * Converts from a disk-stable byte array format to a PersistableBundle + * + * @param bytes the disk-stable byte array + * @return the PersistableBundle parsed from this byte array. + */ + public static PersistableBundle fromDiskStableBytes(@NonNull byte[] bytes) throws IOException { + final ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + return PersistableBundle.readFromStream(inputStream); + } + /** * Ensures safe reading and writing of {@link PersistableBundle}s to and from disk. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index 294f5c1f48..9c6d85238b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -267,6 +267,15 @@ public class PersistableBundleUtilsTest { assertTrue(PersistableBundleUtils.isEqual(testBundle, minimized)); } + @Test + public void testToFromDiskStableBytes() throws Exception { + final PersistableBundle testBundle = getTestBundle(); + final PersistableBundle result = + PersistableBundleUtils.fromDiskStableBytes( + PersistableBundleUtils.toDiskStableBytes(testBundle)); + assertTrue(PersistableBundleUtils.isEqual(testBundle, result)); + } + @Test public void testEquality_identical() throws Exception { final PersistableBundle left = getTestBundle(); From 70e3f01cfc767e95d50703918cab948a59b87214 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 3 May 2022 04:29:38 +0000 Subject: [PATCH 0336/1057] Add to/from disk stable format This change adds a utility to convert persistable bundles to and from disk-stable byte arrays. Bug: 192078259 Test: atest FrameworksVcnTests:PersistableBundleUtilsTest Change-Id: Ifafb7081ec6a34ce3ab8e2aa502d46411405cb6d (cherry picked from commit 2d7894c1f15d13f634a922b64767cecc6ebdf9c5) Merged-In: Ifafb7081ec6a34ce3ab8e2aa502d46411405cb6d --- .../net/vcn/util/PersistableBundleUtils.java | 26 +++++++++++++++++++ .../vcn/util/PersistableBundleUtilsTest.java | 9 +++++++ 2 files changed, 35 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 08e8eebb87..999d4064c9 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -23,6 +23,8 @@ import android.os.PersistableBundle; import com.android.internal.util.HexDump; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -295,6 +297,30 @@ public class PersistableBundleUtils { return result; } + /** + * Converts a PersistableBundle into a disk-stable byte array format + * + * @param bundle the PersistableBundle to be converted to a disk-stable format + * @return the byte array representation of the PersistableBundle + */ + @Nullable + public static byte[] toDiskStableBytes(@NonNull PersistableBundle bundle) throws IOException { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bundle.writeToStream(outputStream); + return outputStream.toByteArray(); + } + + /** + * Converts from a disk-stable byte array format to a PersistableBundle + * + * @param bytes the disk-stable byte array + * @return the PersistableBundle parsed from this byte array. + */ + public static PersistableBundle fromDiskStableBytes(@NonNull byte[] bytes) throws IOException { + final ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + return PersistableBundle.readFromStream(inputStream); + } + /** * Ensures safe reading and writing of {@link PersistableBundle}s to and from disk. * diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java index 294f5c1f48..9c6d85238b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java @@ -267,6 +267,15 @@ public class PersistableBundleUtilsTest { assertTrue(PersistableBundleUtils.isEqual(testBundle, minimized)); } + @Test + public void testToFromDiskStableBytes() throws Exception { + final PersistableBundle testBundle = getTestBundle(); + final PersistableBundle result = + PersistableBundleUtils.fromDiskStableBytes( + PersistableBundleUtils.toDiskStableBytes(testBundle)); + assertTrue(PersistableBundleUtils.isEqual(testBundle, result)); + } + @Test public void testEquality_identical() throws Exception { final PersistableBundle left = getTestBundle(); From 326ef59901f8b33269ed98b58c89f61bc6a91afe Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Thu, 19 May 2022 21:22:37 +0000 Subject: [PATCH 0337/1057] [DO NOT MERGE] Revert "Remove VCN Carrier Privilege grace period" This reverts commit be995271b355ce81b9947068f0abb73ad2e2a5dc. This change brings back the grace period built in VCN because the carrier privileges grace period is turn off. Bug: 229418673 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: I85738c969c2bf78da33beaebe5863432948b7735 --- .../android/server/VcnManagementService.java | 58 +++++++--- .../server/VcnManagementServiceTest.java | 100 ++++++++++++++++-- 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f26d9f9f49..76cac934fd 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -167,6 +168,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { static final String VCN_CONFIG_FILE = new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath(); + // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30); + /* Binder context for this service */ @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; @@ -360,15 +365,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - // Always run on the handler thread to ensure consistency. - mHandler.post(() -> { - mNetworkProvider.register(); - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkCallback( - new NetworkRequest.Builder().clearCapabilities().build(), - mTrackingNetworkCallback); - mTelephonySubscriptionTracker.register(); - }); + mNetworkProvider.register(); + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mTrackingNetworkCallback); + mTelephonySubscriptionTracker.register(); } private void enforcePrimaryUser() { @@ -509,15 +511,22 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!mVcns.containsKey(subGrp)) { startVcnLocked(subGrp, entry.getValue()); } + + // Cancel any scheduled teardowns for active subscriptions + mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } - // Schedule teardown of any VCN instances that have lost carrier privileges + // Schedule teardown of any VCN instances that have lost carrier privileges (after a + // delay) for (Entry entry : mVcns.entrySet()) { final ParcelUuid subGrp = entry.getKey(); final VcnConfig config = mConfigs.get(subGrp); final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); + final boolean isValidActiveDataSubIdNotInVcnSubGrp = + isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) + && !isActiveSubGroup(subGrp, snapshot); // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null @@ -527,12 +536,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); - stopVcnLocked(uuidToTeardown); + // TODO(b/193687515): Support multiple VCNs active at the same time + // If directly switching to a subscription not in the current group, + // teardown immediately to prevent other subscription's network from being + // outscored by the VCN. Otherwise, teardown after a delay to ensure that + // SIM profile switches do not trigger the VCN to cycle. + final long teardownDelayMs = + isValidActiveDataSubIdNotInVcnSubGrp + ? 0 + : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; + mHandler.postDelayed(() -> { + synchronized (mLock) { + // Guard against case where this is run after a old instance was + // torn down, and a new instance was started. Verify to ensure + // correct instance is torn down. This could happen as a result of a + // Carrier App manually removing/adding a VcnConfig. + if (mVcns.get(uuidToTeardown) == instanceToTeardown) { + stopVcnLocked(uuidToTeardown); - // TODO(b/181789060): invoke asynchronously after Vcn notifies - // through VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - uuidToTeardown, VCN_STATUS_CODE_INACTIVE); + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); + } + } + }, instanceToTeardown, teardownDelayMs); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 54b3c400af..f924b2e9b9 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -276,7 +277,6 @@ public class VcnManagementServiceTest { @Test public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); @@ -494,8 +494,10 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - mTestLooper.dispatchAll(); + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); verify(vcn).teardownAsynchronously(); verify(mMockPolicyListener).onPolicyChanged(); } @@ -521,6 +523,92 @@ public class VcnManagementServiceTest { assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); } + /** + * Tests an intermediate state where carrier privileges are marked as lost before active data + * subId changes during a SIM ejection. + * + *

    The expected outcome is that the VCN is torn down after a delay, as opposed to + * immediately. + */ + @Test + public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate privileges lost + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCbAndGetSnapshot( + INVALID_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Simulate new SIM loaded right during teardown delay. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); + mTestLooper.dispatchAll(); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); + + // Verify that even after the full timeout duration, the VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn, never()).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); + + // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new + // vcnInstance. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); + mTestLooper.dispatchAll(); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); + final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Verify that new instance was different, and the old one was torn down + assertTrue(oldInstance != newInstance); + verify(oldInstance).teardownAsynchronously(); + + // Verify that even after the full timeout duration, the new VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(newInstance, never()).teardownAsynchronously(); + } + @Test public void testPackageChangeListenerRegistered() throws Exception { verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { @@ -910,8 +998,6 @@ public class VcnManagementServiceTest { private void setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot( subGrp, Collections.singleton(subGrp), @@ -1007,7 +1093,6 @@ public class VcnManagementServiceTest { private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); final ArgumentCaptor captor = ArgumentCaptor.forClass(NetworkCallback.class); @@ -1252,14 +1337,15 @@ public class VcnManagementServiceTest { true /* isActive */, true /* hasCarrierPrivileges */); - // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes - // inactive. + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown + // timeout so the VCN goes inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE From b82fafdfb281f10534e79a6a8bf65277c0bc4ca1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 12 Aug 2022 04:19:08 +0000 Subject: [PATCH 0338/1057] Add three new IKE options in IkeSessionParamsUtils This commit updates IkeSessionParamsUtils to be able to encode/decode IkeSessionParams with IKE_OPTION_REKEY_MOBILITY, IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION and IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES Bug: 242231517 Test: atest IkeSessionParamsUtilsTest Change-Id: I0ea9fbf1e0c304a5afb563f912d2a8a49b4faad0 --- .../IkeSessionParamsUtils.java | 10 ++++++ .../IkeSessionParamsUtilsTest.java | 36 +++++++++++-------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index be57372193..b2e75a36c3 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -72,6 +72,13 @@ public final class IkeSessionParamsUtils { private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; + // TODO: Use the IKE API when they are exposed + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7; + private static final Set IKE_OPTIONS = new ArraySet<>(); static { @@ -80,6 +87,9 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); } /** Serializes an IkeSessionParams to a PersistableBundle. */ diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 3b201f9d20..d2f0a20fc3 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -134,13 +134,33 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } + private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception { + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + + final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); + final int subId = 1; + final EapSessionConfig eapConfig = + new EapSessionConfig.Builder() + .setEapIdentity(eapId) + .setEapSimConfig(subId, APPTYPE_USIM) + .setEapAkaConfig(subId, APPTYPE_USIM) + .build(); + return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig); + } + @Test public void testEncodeDecodeParamsWithIkeOptions() throws Exception { final IkeSessionParams params = - createBuilderMinimum() + createBuilderMinimumWithEap() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) + .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY) + .addIkeOption( + IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION) + .addIkeOption(IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @@ -176,19 +196,7 @@ public class IkeSessionParamsUtilsTest { @Test public void testEncodeRecodeParamsWithEapAuth() throws Exception { - final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); - - final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); - final int subId = 1; - final EapSessionConfig eapConfig = - new EapSessionConfig.Builder() - .setEapIdentity(eapId) - .setEapSimConfig(subId, APPTYPE_USIM) - .setEapAkaConfig(subId, APPTYPE_USIM) - .build(); - - final IkeSessionParams params = - createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build(); + final IkeSessionParams params = createBuilderMinimumWithEap().build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } } From 34bebda9cdd45680d74e3451115e91f70d6d2c4d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Aug 2022 17:55:20 +0000 Subject: [PATCH 0339/1057] Revert "Add three new IKE options in IkeSessionParamsUtils" This reverts commit b82fafdfb281f10534e79a6a8bf65277c0bc4ca1. Reason for revert: This commit will be cherry picked for QPR release and is accessing new IPsec API constants that will not be released until mainline October train. This commit fails to maintain the compatibility with IPsec module that is older than the October version. Bug: 242231517 Test: atest IkeSessionParamsUtilsTest Change-Id: Iff0dcc32025dad3016257655205beaf2e842f24c --- .../IkeSessionParamsUtils.java | 10 ------ .../IkeSessionParamsUtilsTest.java | 36 ++++++++----------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index b2e75a36c3..be57372193 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -72,13 +72,6 @@ public final class IkeSessionParamsUtils { private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; - // TODO: Use the IKE API when they are exposed - @VisibleForTesting(visibility = Visibility.PRIVATE) - public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6; - - @VisibleForTesting(visibility = Visibility.PRIVATE) - public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7; - private static final Set IKE_OPTIONS = new ArraySet<>(); static { @@ -87,9 +80,6 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); - IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); - IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); - IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); } /** Serializes an IkeSessionParams to a PersistableBundle. */ diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index d2f0a20fc3..3b201f9d20 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -134,33 +134,13 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } - private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception { - final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); - - final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); - final int subId = 1; - final EapSessionConfig eapConfig = - new EapSessionConfig.Builder() - .setEapIdentity(eapId) - .setEapSimConfig(subId, APPTYPE_USIM) - .setEapAkaConfig(subId, APPTYPE_USIM) - .build(); - return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig); - } - @Test public void testEncodeDecodeParamsWithIkeOptions() throws Exception { final IkeSessionParams params = - createBuilderMinimumWithEap() + createBuilderMinimum() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) - .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) - .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) - .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY) - .addIkeOption( - IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION) - .addIkeOption(IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @@ -196,7 +176,19 @@ public class IkeSessionParamsUtilsTest { @Test public void testEncodeRecodeParamsWithEapAuth() throws Exception { - final IkeSessionParams params = createBuilderMinimumWithEap().build(); + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + + final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); + final int subId = 1; + final EapSessionConfig eapConfig = + new EapSessionConfig.Builder() + .setEapIdentity(eapId) + .setEapSimConfig(subId, APPTYPE_USIM) + .setEapAkaConfig(subId, APPTYPE_USIM) + .build(); + + final IkeSessionParams params = + createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } } From 566ea82c54b82a0166d0b94dce76f213f15c85f2 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Aug 2022 20:03:36 +0000 Subject: [PATCH 0340/1057] Add three new IKE options in IkeSessionParamsUtils This commit updates IkeSessionParamsUtils to be able to encode/decode IkeSessionParams with IKE_OPTION_REKEY_MOBILITY, IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION and IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES. This commit can also maintain compatibility with older T IPsec modules that do not support the two IKE_OPTION_AUTOMATIC_ options Bug: 242231517 Test: atest IkeSessionParamsUtilsTest Change-Id: Icadbe98b3df3cf3a80f51dc1467eb99753d82216 --- .../IkeSessionParamsUtils.java | 40 ++++++++++++++-- .../IkeSessionParamsUtilsTest.java | 47 ++++++++++++------- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index be57372193..d6f191e311 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -37,6 +37,7 @@ import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import android.os.PersistableBundle; import android.util.ArraySet; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; @@ -58,6 +59,8 @@ import java.util.Set; */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class IkeSessionParamsUtils { + private static final String TAG = IkeSessionParamsUtils.class.getSimpleName(); + private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY"; private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; @@ -72,6 +75,13 @@ public final class IkeSessionParamsUtils { private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; + // TODO: b/243181760 Use the IKE API when they are exposed + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7; + private static final Set IKE_OPTIONS = new ArraySet<>(); static { @@ -80,6 +90,26 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); + } + + /** + * Check if an IKE option is supported in the IPsec module installed on the device + * + *

    This method ensures caller to safely access options that are added between dessert + * releases. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static boolean isIkeOptionValid(int option) { + try { + new IkeSessionParams.Builder().addIkeOption(option); + return true; + } catch (IllegalArgumentException e) { + Log.d(TAG, "Option not supported; discarding: " + option); + return false; + } } /** Serializes an IkeSessionParams to a PersistableBundle. */ @@ -130,7 +160,7 @@ public final class IkeSessionParamsUtils { // IKE_OPTION is defined in IKE module and added in the IkeSessionParams final List enabledIkeOptions = new ArrayList<>(); for (int option : IKE_OPTIONS) { - if (params.hasIkeOption(option)) { + if (isIkeOptionValid(option) && params.hasIkeOption(option)) { enabledIkeOptions.add(option); } } @@ -205,12 +235,16 @@ public final class IkeSessionParamsUtils { // Clear IKE Options that are by default enabled for (int option : IKE_OPTIONS) { - builder.removeIkeOption(option); + if (isIkeOptionValid(option)) { + builder.removeIkeOption(option); + } } final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY); for (int option : optionArray) { - builder.addIkeOption(option); + if (isIkeOptionValid(option)) { + builder.addIkeOption(option); + } } return builder.build(); diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 3b201f9d20..e4add80981 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -16,6 +16,9 @@ package android.net.vcn.persistablebundleutils; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.isIkeOptionValid; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.telephony.TelephonyManager.APPTYPE_USIM; @@ -134,15 +137,37 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } + private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception { + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + + final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); + final int subId = 1; + final EapSessionConfig eapConfig = + new EapSessionConfig.Builder() + .setEapIdentity(eapId) + .setEapSimConfig(subId, APPTYPE_USIM) + .setEapAkaConfig(subId, APPTYPE_USIM) + .build(); + return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig); + } + @Test public void testEncodeDecodeParamsWithIkeOptions() throws Exception { - final IkeSessionParams params = - createBuilderMinimum() + final IkeSessionParams.Builder builder = + createBuilderMinimumWithEap() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) - .build(); - verifyPersistableBundleEncodeDecodeIsLossless(params); + .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); + if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)) { + builder.addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); + } + if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) { + builder.addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); + } + verifyPersistableBundleEncodeDecodeIsLossless(builder.build()); } private static InputStream openAssetsFile(String fileName) throws Exception { @@ -176,19 +201,7 @@ public class IkeSessionParamsUtilsTest { @Test public void testEncodeRecodeParamsWithEapAuth() throws Exception { - final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); - - final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); - final int subId = 1; - final EapSessionConfig eapConfig = - new EapSessionConfig.Builder() - .setEapIdentity(eapId) - .setEapSimConfig(subId, APPTYPE_USIM) - .setEapAkaConfig(subId, APPTYPE_USIM) - .build(); - - final IkeSessionParams params = - createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build(); + final IkeSessionParams params = createBuilderMinimumWithEap().build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } } From a4b470aaa32a052e23ed727186934c9889e38b2e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 19 Aug 2022 20:03:36 +0000 Subject: [PATCH 0341/1057] Add three new IKE options in IkeSessionParamsUtils This commit updates IkeSessionParamsUtils to be able to encode/decode IkeSessionParams with IKE_OPTION_REKEY_MOBILITY, IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION and IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES. This commit can also maintain compatibility with older T IPsec modules that do not support the two IKE_OPTION_AUTOMATIC_ options Bug: 242231517 Test: atest IkeSessionParamsUtilsTest Change-Id: Icadbe98b3df3cf3a80f51dc1467eb99753d82216 (cherry picked from commit 566ea82c54b82a0166d0b94dce76f213f15c85f2) Merged-In: Icadbe98b3df3cf3a80f51dc1467eb99753d82216 --- .../IkeSessionParamsUtils.java | 40 ++++++++++++++-- .../IkeSessionParamsUtilsTest.java | 47 ++++++++++++------- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index be57372193..d6f191e311 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -37,6 +37,7 @@ import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; import android.os.PersistableBundle; import android.util.ArraySet; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; @@ -58,6 +59,8 @@ import java.util.Set; */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class IkeSessionParamsUtils { + private static final String TAG = IkeSessionParamsUtils.class.getSimpleName(); + private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY"; private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; @@ -72,6 +75,13 @@ public final class IkeSessionParamsUtils { private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; + // TODO: b/243181760 Use the IKE API when they are exposed + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7; + private static final Set IKE_OPTIONS = new ArraySet<>(); static { @@ -80,6 +90,26 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); + IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); + } + + /** + * Check if an IKE option is supported in the IPsec module installed on the device + * + *

    This method ensures caller to safely access options that are added between dessert + * releases. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static boolean isIkeOptionValid(int option) { + try { + new IkeSessionParams.Builder().addIkeOption(option); + return true; + } catch (IllegalArgumentException e) { + Log.d(TAG, "Option not supported; discarding: " + option); + return false; + } } /** Serializes an IkeSessionParams to a PersistableBundle. */ @@ -130,7 +160,7 @@ public final class IkeSessionParamsUtils { // IKE_OPTION is defined in IKE module and added in the IkeSessionParams final List enabledIkeOptions = new ArrayList<>(); for (int option : IKE_OPTIONS) { - if (params.hasIkeOption(option)) { + if (isIkeOptionValid(option) && params.hasIkeOption(option)) { enabledIkeOptions.add(option); } } @@ -205,12 +235,16 @@ public final class IkeSessionParamsUtils { // Clear IKE Options that are by default enabled for (int option : IKE_OPTIONS) { - builder.removeIkeOption(option); + if (isIkeOptionValid(option)) { + builder.removeIkeOption(option); + } } final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY); for (int option : optionArray) { - builder.addIkeOption(option); + if (isIkeOptionValid(option)) { + builder.addIkeOption(option); + } } return builder.build(); diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 3b201f9d20..e4add80981 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -16,6 +16,9 @@ package android.net.vcn.persistablebundleutils; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES; +import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.isIkeOptionValid; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.telephony.TelephonyManager.APPTYPE_USIM; @@ -134,15 +137,37 @@ public class IkeSessionParamsUtilsTest { verifyPersistableBundleEncodeDecodeIsLossless(params); } + private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception { + final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); + + final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); + final int subId = 1; + final EapSessionConfig eapConfig = + new EapSessionConfig.Builder() + .setEapIdentity(eapId) + .setEapSimConfig(subId, APPTYPE_USIM) + .setEapAkaConfig(subId, APPTYPE_USIM) + .build(); + return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig); + } + @Test public void testEncodeDecodeParamsWithIkeOptions() throws Exception { - final IkeSessionParams params = - createBuilderMinimum() + final IkeSessionParams.Builder builder = + createBuilderMinimumWithEap() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) + .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) - .build(); - verifyPersistableBundleEncodeDecodeIsLossless(params); + .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); + if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)) { + builder.addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); + } + if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) { + builder.addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); + } + verifyPersistableBundleEncodeDecodeIsLossless(builder.build()); } private static InputStream openAssetsFile(String fileName) throws Exception { @@ -176,19 +201,7 @@ public class IkeSessionParamsUtilsTest { @Test public void testEncodeRecodeParamsWithEapAuth() throws Exception { - final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); - - final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); - final int subId = 1; - final EapSessionConfig eapConfig = - new EapSessionConfig.Builder() - .setEapIdentity(eapId) - .setEapSimConfig(subId, APPTYPE_USIM) - .setEapAkaConfig(subId, APPTYPE_USIM) - .build(); - - final IkeSessionParams params = - createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build(); + final IkeSessionParams params = createBuilderMinimumWithEap().build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } } From 22fc2250d918d6b7a67353333304e753ac7e3d7e Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Thu, 19 May 2022 21:22:37 +0000 Subject: [PATCH 0342/1057] Revert "Remove VCN Carrier Privilege grace period" This reverts commit be995271b355ce81b9947068f0abb73ad2e2a5dc. This change brings back the grace period built in VCN because the carrier privileges grace period is turn off. Bug: 229418673 Test: atest FrameworksVcnTests CtsVcnTestCases Merged-In: I85738c969c2bf78da33beaebe5863432948b7735 Change-Id: I85738c969c2bf78da33beaebe5863432948b7735 (cherry picked from commit 326ef59901f8b33269ed98b58c89f61bc6a91afe) --- .../android/server/VcnManagementService.java | 58 +++++++--- .../server/VcnManagementServiceTest.java | 100 ++++++++++++++++-- 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f26d9f9f49..76cac934fd 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -167,6 +168,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { static final String VCN_CONFIG_FILE = new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath(); + // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30); + /* Binder context for this service */ @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; @@ -360,15 +365,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - // Always run on the handler thread to ensure consistency. - mHandler.post(() -> { - mNetworkProvider.register(); - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkCallback( - new NetworkRequest.Builder().clearCapabilities().build(), - mTrackingNetworkCallback); - mTelephonySubscriptionTracker.register(); - }); + mNetworkProvider.register(); + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mTrackingNetworkCallback); + mTelephonySubscriptionTracker.register(); } private void enforcePrimaryUser() { @@ -509,15 +511,22 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!mVcns.containsKey(subGrp)) { startVcnLocked(subGrp, entry.getValue()); } + + // Cancel any scheduled teardowns for active subscriptions + mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } - // Schedule teardown of any VCN instances that have lost carrier privileges + // Schedule teardown of any VCN instances that have lost carrier privileges (after a + // delay) for (Entry entry : mVcns.entrySet()) { final ParcelUuid subGrp = entry.getKey(); final VcnConfig config = mConfigs.get(subGrp); final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot); + final boolean isValidActiveDataSubIdNotInVcnSubGrp = + isValidSubscriptionId(snapshot.getActiveDataSubscriptionId()) + && !isActiveSubGroup(subGrp, snapshot); // TODO(b/193687515): Support multiple VCNs active at the same time if (config == null @@ -527,12 +536,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { final ParcelUuid uuidToTeardown = subGrp; final Vcn instanceToTeardown = entry.getValue(); - stopVcnLocked(uuidToTeardown); + // TODO(b/193687515): Support multiple VCNs active at the same time + // If directly switching to a subscription not in the current group, + // teardown immediately to prevent other subscription's network from being + // outscored by the VCN. Otherwise, teardown after a delay to ensure that + // SIM profile switches do not trigger the VCN to cycle. + final long teardownDelayMs = + isValidActiveDataSubIdNotInVcnSubGrp + ? 0 + : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS; + mHandler.postDelayed(() -> { + synchronized (mLock) { + // Guard against case where this is run after a old instance was + // torn down, and a new instance was started. Verify to ensure + // correct instance is torn down. This could happen as a result of a + // Carrier App manually removing/adding a VcnConfig. + if (mVcns.get(uuidToTeardown) == instanceToTeardown) { + stopVcnLocked(uuidToTeardown); - // TODO(b/181789060): invoke asynchronously after Vcn notifies - // through VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - uuidToTeardown, VCN_STATUS_CODE_INACTIVE); + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); + } + } + }, instanceToTeardown, teardownDelayMs); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 54b3c400af..f924b2e9b9 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -276,7 +277,6 @@ public class VcnManagementServiceTest { @Test public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); @@ -494,8 +494,10 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - mTestLooper.dispatchAll(); + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); verify(vcn).teardownAsynchronously(); verify(mMockPolicyListener).onPolicyChanged(); } @@ -521,6 +523,92 @@ public class VcnManagementServiceTest { assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); } + /** + * Tests an intermediate state where carrier privileges are marked as lost before active data + * subId changes during a SIM ejection. + * + *

    The expected outcome is that the VCN is torn down after a delay, as opposed to + * immediately. + */ + @Test + public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate privileges lost + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Verify teardown after delay + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() + throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCbAndGetSnapshot( + INVALID_SUBSCRIPTION_ID, + null /* activeDataSubscriptionGroup */, + Collections.emptySet(), + Collections.emptyMap(), + false /* hasCarrierPrivileges */); + + // Simulate new SIM loaded right during teardown delay. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); + mTestLooper.dispatchAll(); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); + + // Verify that even after the full timeout duration, the VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(vcn, never()).teardownAsynchronously(); + } + + @Test + public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { + setupActiveSubscription(TEST_UUID_2); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Simulate SIM unloaded + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); + + // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new + // vcnInstance. + mTestLooper.moveTimeForward( + VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); + mTestLooper.dispatchAll(); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); + final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); + + // Verify that new instance was different, and the old one was torn down + assertTrue(oldInstance != newInstance); + verify(oldInstance).teardownAsynchronously(); + + // Verify that even after the full timeout duration, the new VCN instance is not torn down + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + verify(newInstance, never()).teardownAsynchronously(); + } + @Test public void testPackageChangeListenerRegistered() throws Exception { verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { @@ -910,8 +998,6 @@ public class VcnManagementServiceTest { private void setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot( subGrp, Collections.singleton(subGrp), @@ -1007,7 +1093,6 @@ public class VcnManagementServiceTest { private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { mVcnMgmtSvc.systemReady(); - mTestLooper.dispatchAll(); final ArgumentCaptor captor = ArgumentCaptor.forClass(NetworkCallback.class); @@ -1252,14 +1337,15 @@ public class VcnManagementServiceTest { true /* isActive */, true /* hasCarrierPrivileges */); - // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes - // inactive. + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown + // timeout so the VCN goes inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE From 2ad4b419ba7110565bd50a93d788c21e739161dc Mon Sep 17 00:00:00 2001 From: Sandro Date: Fri, 4 Nov 2022 16:09:53 +0000 Subject: [PATCH 0343/1057] Add run_on_sdk_sandbox optional tag to CTS tests See go/sdk-sandbox-cts-tag Tagging CTS tests for services used by sdk_sandbox http://cs/android-internal/system/sepolicy/private/sdk_sandbox.te;l=141-212;rcl=8c88531dd84a7cbc89cb65e1520c24c6248dad86 Bug: 253447284 Test: Compile and start CTS cli, then "run cts --enable-optional-parameterization" Change-Id: I191b8b38042066ceef003dd5bcb5520d54f618ce --- Vcn/tests/cts/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/AndroidTest.xml b/Vcn/tests/cts/AndroidTest.xml index 4b431b3257..286a671d5b 100644 --- a/Vcn/tests/cts/AndroidTest.xml +++ b/Vcn/tests/cts/AndroidTest.xml @@ -20,6 +20,7 @@

    Defaults to TRANSPORT_WIFI if the config does not exist + * + * @hide + */ + public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY = + "vcn_restricted_transports"; + /** List of Carrier Config options to extract from Carrier Config bundles. @hide */ @NonNull public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS = new String[] { VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, - VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY + VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY }; private static final Map< diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 999d4064c9..d22ec0ad45 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -544,6 +544,20 @@ public class PersistableBundleUtils { return mBundle.getInt(key, defaultValue); } + /** + * Returns the value associated with the given key, or null if no mapping of the desired + * type exists for the given key or a null value is explicitly associated with the key. + * + * @param key a String, or null + * @param defaultValue the value to return if key does not exist + * @return an int[] value, or null + */ + @Nullable + public int[] getIntArray(@Nullable String key, @Nullable int[] defaultValue) { + final int[] value = mBundle.getIntArray(key); + return value == null ? defaultValue : value; + } + @Override public int hashCode() { return getHashCode(mBundle); diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 6f49db1adb..61f7f301a8 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES; +import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; @@ -55,6 +56,7 @@ import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.Binder; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -86,6 +88,7 @@ import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; +import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.io.File; import java.io.FileDescriptor; @@ -162,6 +165,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int LOCAL_LOG_LINE_COUNT = 512; + private static final Set RESTRICTED_TRANSPORTS_DEFAULT = + Collections.singleton(TRANSPORT_WIFI); + // Public for use in all other VCN classes @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT); @@ -367,12 +373,30 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Gets the transports that need to be marked as restricted by the VCN */ public Set getRestrictedTransports( - ParcelUuid subGrp, - Map vcnConfigs, - TelephonySubscriptionSnapshot lastSnapshot) { - // TODO: b/239104955 Read restriction policy configurations + ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) { + if (!Build.IS_ENG && !Build.IS_USERDEBUG) { + return RESTRICTED_TRANSPORTS_DEFAULT; + } - return Collections.singleton(TRANSPORT_WIFI); + final PersistableBundleWrapper carrierConfig = + lastSnapshot.getCarrierConfigForSubGrp(subGrp); + if (carrierConfig == null) { + return RESTRICTED_TRANSPORTS_DEFAULT; + } + + final int[] defaultValue = + RESTRICTED_TRANSPORTS_DEFAULT.stream().mapToInt(i -> i).toArray(); + final int[] restrictedTransportsArray = + carrierConfig.getIntArray( + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + defaultValue); + + // Convert to a boxed set + final Set restrictedTransports = new ArraySet<>(); + for (int transport : restrictedTransportsArray) { + restrictedTransports.add(transport); + } + return restrictedTransports; } } @@ -530,6 +554,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + boolean needNotifyAllPolicyListeners = false; // Schedule teardown of any VCN instances that have lost carrier privileges (after a // delay) for (Entry entry : mVcns.entrySet()) { @@ -577,6 +602,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); + needNotifyAllPolicyListeners |= + !Objects.equals( + oldSnapshot.getCarrierConfigForSubGrp(subGrp), + mLastSnapshot.getCarrierConfigForSubGrp(subGrp)); } } @@ -586,6 +615,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { getSubGroupToSubIdMappings(mLastSnapshot); if (!currSubGrpMappings.equals(oldSubGrpMappings)) { garbageCollectAndWriteVcnConfigsLocked(); + needNotifyAllPolicyListeners = true; + } + + if (needNotifyAllPolicyListeners) { notifyAllPolicyListenersLocked(); } } @@ -930,6 +963,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void addVcnUnderlyingNetworkPolicyListenerForTest( + @NonNull IVcnUnderlyingNetworkPolicyListener listener) { + synchronized (mLock) { + addVcnUnderlyingNetworkPolicyListener(listener); + } + } + /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ @GuardedBy("mLock") @Override @@ -1022,7 +1063,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { } final Set restrictedTransports = - mDeps.getRestrictedTransports(subGrp, mConfigs, mLastSnapshot); + mDeps.getRestrictedTransports(subGrp, mLastSnapshot); for (int restrictedTransport : restrictedTransports) { if (ncCopy.hasTransport(restrictedTransport)) { if (restrictedTransport == TRANSPORT_CELLULAR) { diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 5c305c6902..ca4a32f553 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -390,8 +390,13 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null"); - mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap); - mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap); + mSubIdToInfoMap = + Collections.unmodifiableMap( + new HashMap(subIdToInfoMap)); + mSubIdToCarrierConfigMap = + Collections.unmodifiableMap( + new HashMap( + subIdToCarrierConfigMap)); final Map> unmodifiableInnerSets = new ArrayMap<>(); for (Entry> entry : privilegedPackages.entrySet()) { diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 478afe8aed..eae8873eba 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -96,6 +97,7 @@ import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.util.PersistableBundleUtils; +import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import org.junit.Before; import org.junit.Test; @@ -256,7 +258,7 @@ public class VcnManagementServiceTest { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) - .getRestrictedTransports(any(), any(), any()); + .getRestrictedTransports(any(), any()); } @@ -1037,6 +1039,59 @@ public class VcnManagementServiceTest { new LinkProperties()); } + private void checkGetRestrictedTransports( + ParcelUuid subGrp, + TelephonySubscriptionSnapshot lastSnapshot, + Set expectedTransports) { + Set result = + new VcnManagementService.Dependencies() + .getRestrictedTransports(subGrp, lastSnapshot); + assertEquals(expectedTransports, result); + } + + @Test + public void testGetRestrictedTransports() { + final Set restrictedTransports = new ArraySet<>(); + restrictedTransports.add(TRANSPORT_CELLULAR); + restrictedTransports.add(TRANSPORT_WIFI); + + PersistableBundle carrierConfigBundle = new PersistableBundle(); + carrierConfigBundle.putIntArray( + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + restrictedTransports.stream().mapToInt(i -> i).toArray()); + final PersistableBundleWrapper carrierConfig = + new PersistableBundleWrapper(carrierConfigBundle); + + final TelephonySubscriptionSnapshot lastSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); + + checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + } + + @Test + public void testGetRestrictedTransports_noRestrictPolicyConfigured() { + final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI); + + final PersistableBundleWrapper carrierConfig = + new PersistableBundleWrapper(new PersistableBundle()); + final TelephonySubscriptionSnapshot lastSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); + + checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + } + + @Test + public void testGetRestrictedTransports_noCarrierConfig() { + final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI); + + final TelephonySubscriptionSnapshot lastSnapshot = + mock(TelephonySubscriptionSnapshot.class); + + checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + } + private void checkGetUnderlyingNetworkPolicy( int transportType, boolean isTransportRestricted, @@ -1049,7 +1104,7 @@ public class VcnManagementServiceTest { if (isTransportRestricted) { restrictedTransports.add(transportType); } - doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any(), any()); + doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any()); final VcnUnderlyingNetworkPolicy policy = startVcnAndGetPolicyForTransport( @@ -1147,7 +1202,7 @@ public class VcnManagementServiceTest { public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) - .getRestrictedTransports(any(), any(), any()); + .getRestrictedTransports(any(), any()); setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */); @@ -1316,6 +1371,30 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener); + + final TelephonySubscriptionSnapshot snapshot = + buildSubscriptionSnapshot( + TEST_SUBSCRIPTION_ID, + TEST_UUID_2, + Collections.singleton(TEST_UUID_2), + Collections.emptyMap(), + true /* hasCarrierPrivileges */); + + final PersistableBundleWrapper mockCarrierConfig = mock(PersistableBundleWrapper.class); + doReturn(mockCarrierConfig).when(snapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); + + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); + cb.onNewSnapshot(snapshot); + + verify(mMockPolicyListener).onPolicyChanged(); + } + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 09080be9ee..965b073ff0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -16,6 +16,9 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; @@ -39,6 +42,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -493,6 +497,37 @@ public class TelephonySubscriptionTrackerTest { verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap()))); } + @Test + public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception { + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); + reset(mCallback); + + final PersistableBundle updatedConfig = new PersistableBundle(); + updatedConfig.putIntArray( + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR}); + doReturn(updatedConfig) + .when(mCarrierConfigManager) + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); + + Map subIdToCarrierConfigMap = new HashMap<>(); + subIdToCarrierConfigMap.put( + TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig)); + mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + mTestLooper.dispatchAll(); + + verify(mCallback) + .onNewSnapshot( + eq( + buildExpectedSnapshot( + 0, + TEST_SUBID_TO_INFO_MAP, + subIdToCarrierConfigMap, + TEST_PRIVILEGED_PACKAGES))); + } + @Test public void testSlotClearedAfterValidTriggersCallbacks() throws Exception { mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); From 7352d96f2746ade15aaea9eecdcf770529b04ecd Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 27 Oct 2022 23:53:57 +0000 Subject: [PATCH 0347/1057] Add restrictions on underlying networks with VcnConfig This commit allows VCN callers to configure underlying networks that need to be restricted via VcnConfig. This commit also makes sure that VCN will notify policy listners when the VcnConfig gets updated. Bug: 239104955 Test: atest FrameworksVcnTests(new tests) Test: atest CtsVcnTestCases Change-Id: Ie174f7ec27ba115939c4f5d88d9bb00c6d348ea9 --- .../src/android/net/vcn/VcnConfig.java | 109 +++++++++++++++++- .../android/server/VcnManagementService.java | 36 +++--- .../java/android/net/vcn/VcnConfigTest.java | 59 +++++++++- .../server/VcnManagementServiceTest.java | 79 +++++++++++-- 4 files changed, 253 insertions(+), 30 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index fd3fe3731b..8627f5c7a1 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -15,7 +15,12 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import static com.android.internal.annotations.VisibleForTesting.Visibility; +import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; +import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; import android.annotation.NonNull; import android.annotation.Nullable; @@ -25,6 +30,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; import android.util.ArraySet; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; @@ -32,6 +38,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.Objects; import java.util.Set; @@ -46,22 +53,36 @@ import java.util.Set; public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); + private static final Set ALLOWED_TRANSPORTS = new ArraySet<>(); + + static { + ALLOWED_TRANSPORTS.add(TRANSPORT_WIFI); + ALLOWED_TRANSPORTS.add(TRANSPORT_CELLULAR); + } + private static final String PACKAGE_NAME_KEY = "mPackageName"; @NonNull private final String mPackageName; private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; @NonNull private final Set mGatewayConnectionConfigs; + private static final Set RESTRICTED_TRANSPORTS_DEFAULT = + Collections.singleton(TRANSPORT_WIFI); + private static final String RESTRICTED_TRANSPORTS_KEY = "mRestrictedTransports"; + @NonNull private final Set mRestrictedTransports; + private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile"; private final boolean mIsTestModeProfile; private VcnConfig( @NonNull String packageName, @NonNull Set gatewayConnectionConfigs, + @NonNull Set restrictedTransports, boolean isTestModeProfile) { mPackageName = packageName; mGatewayConnectionConfigs = Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs)); + mRestrictedTransports = Collections.unmodifiableSet(new ArraySet<>(restrictedTransports)); mIsTestModeProfile = isTestModeProfile; validate(); @@ -82,6 +103,20 @@ public final class VcnConfig implements Parcelable { new ArraySet<>( PersistableBundleUtils.toList( gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); + + final PersistableBundle restrictedTransportsBundle = + in.getPersistableBundle(RESTRICTED_TRANSPORTS_KEY); + if (restrictedTransportsBundle == null) { + // RESTRICTED_TRANSPORTS_KEY was added in U and does not exist in VcnConfigs created in + // older platforms + mRestrictedTransports = RESTRICTED_TRANSPORTS_DEFAULT; + } else { + mRestrictedTransports = + new ArraySet( + PersistableBundleUtils.toList( + restrictedTransportsBundle, INTEGER_DESERIALIZER)); + } + mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY); validate(); @@ -91,6 +126,19 @@ public final class VcnConfig implements Parcelable { Objects.requireNonNull(mPackageName, "packageName was null"); Preconditions.checkCollectionNotEmpty( mGatewayConnectionConfigs, "gatewayConnectionConfigs was empty"); + + final Iterator iterator = mRestrictedTransports.iterator(); + while (iterator.hasNext()) { + final int transport = iterator.next(); + if (!ALLOWED_TRANSPORTS.contains(transport)) { + iterator.remove(); + Log.w( + TAG, + "Found invalid transport " + + transport + + " which might be from a new version of VcnConfig"); + } + } } /** @@ -109,6 +157,17 @@ public final class VcnConfig implements Parcelable { return Collections.unmodifiableSet(mGatewayConnectionConfigs); } + /** + * Retrieve the transports that need to be restricted by VCN. + * + * @see Builder#setRestrictedUnderlyingNetworkTransports(Set) + * @hide + */ + @NonNull + public Set getRestrictedUnderlyingNetworkTransports() { + return Collections.unmodifiableSet(mRestrictedTransports); + } + /** * Returns whether or not this VcnConfig is restricted to test networks. * @@ -134,6 +193,12 @@ public final class VcnConfig implements Parcelable { new ArrayList<>(mGatewayConnectionConfigs), VcnGatewayConnectionConfig::toPersistableBundle); result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); + + final PersistableBundle restrictedTransportsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mRestrictedTransports), INTEGER_SERIALIZER); + result.putPersistableBundle(RESTRICTED_TRANSPORTS_KEY, restrictedTransportsBundle); + result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile); return result; @@ -141,7 +206,8 @@ public final class VcnConfig implements Parcelable { @Override public int hashCode() { - return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); + return Objects.hash( + mPackageName, mGatewayConnectionConfigs, mRestrictedTransports, mIsTestModeProfile); } @Override @@ -153,6 +219,7 @@ public final class VcnConfig implements Parcelable { final VcnConfig rhs = (VcnConfig) other; return mPackageName.equals(rhs.mPackageName) && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs) + && mRestrictedTransports.equals(rhs.mRestrictedTransports) && mIsTestModeProfile == rhs.mIsTestModeProfile; } @@ -189,12 +256,15 @@ public final class VcnConfig implements Parcelable { @NonNull private final Set mGatewayConnectionConfigs = new ArraySet<>(); + @NonNull private final Set mRestrictedTransports = new ArraySet<>(); + private boolean mIsTestModeProfile = false; public Builder(@NonNull Context context) { Objects.requireNonNull(context, "context was null"); mPackageName = context.getOpPackageName(); + mRestrictedTransports.addAll(RESTRICTED_TRANSPORTS_DEFAULT); } /** @@ -225,6 +295,37 @@ public final class VcnConfig implements Parcelable { return this; } + private void validateRestrictedTransportsOrThrow(Set restrictedTransports) { + Objects.requireNonNull(restrictedTransports, "transports was null"); + + for (int transport : restrictedTransports) { + if (!ALLOWED_TRANSPORTS.contains(transport)) { + throw new IllegalArgumentException("Invalid transport " + transport); + } + } + } + + /** + * Sets transports that need to be restricted by VCN. + * + * @param transports transports that need to be restricted by VCN. Networks that include any + * of the transports will be marked as restricted. Only {@link + * NetworkCapabilities#TRANSPORT_WIFI} and {@link + * NetworkCapabilities#TRANSPORT_CELLULAR} are allowed. {@link + * NetworkCapabilities#TRANSPORT_WIFI} is marked restricted by default. + * @return this {@link Builder} instance, for chaining + * @throws IllegalArgumentException if the input contains unsupported transport types. + * @hide + */ + @NonNull + public Builder setRestrictedUnderlyingNetworkTransports(@NonNull Set transports) { + validateRestrictedTransportsOrThrow(transports); + + mRestrictedTransports.clear(); + mRestrictedTransports.addAll(transports); + return this; + } + /** * Restricts this VcnConfig to matching with test networks (only). * @@ -248,7 +349,11 @@ public final class VcnConfig implements Parcelable { */ @NonNull public VcnConfig build() { - return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); + return new VcnConfig( + mPackageName, + mGatewayConnectionConfigs, + mRestrictedTransports, + mIsTestModeProfile); } } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 61f7f301a8..f652cb050c 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -371,8 +371,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { return new LocationPermissionChecker(context); } - /** Gets the transports that need to be marked as restricted by the VCN */ - public Set getRestrictedTransports( + /** Gets transports that need to be marked as restricted by the VCN from CarrierConfig */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Set getRestrictedTransportsFromCarrierConfig( ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) { if (!Build.IS_ENG && !Build.IS_USERDEBUG) { return RESTRICTED_TRANSPORTS_DEFAULT; @@ -398,6 +399,22 @@ public class VcnManagementService extends IVcnManagementService.Stub { } return restrictedTransports; } + + /** Gets the transports that need to be marked as restricted by the VCN */ + public Set getRestrictedTransports( + ParcelUuid subGrp, + TelephonySubscriptionSnapshot lastSnapshot, + VcnConfig vcnConfig) { + final Set restrictedTransports = new ArraySet<>(); + restrictedTransports.addAll(vcnConfig.getRestrictedUnderlyingNetworkTransports()); + + // TODO: b/262269892 Remove the ability to configure restricted transports + // via CarrierConfig + restrictedTransports.addAll( + getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot)); + + return restrictedTransports; + } } /** Notifies the VcnManagementService that external dependencies can be set up. */ @@ -719,6 +736,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); vcn.updateConfig(config); + notifyAllPolicyListenersLocked(); } else { // TODO(b/193687515): Support multiple VCNs active at the same time if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) { @@ -936,7 +954,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { } /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */ - @GuardedBy("mLock") @Override public void addVcnUnderlyingNetworkPolicyListener( @NonNull IVcnUnderlyingNetworkPolicyListener listener) { @@ -963,16 +980,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } - @VisibleForTesting(visibility = Visibility.PRIVATE) - void addVcnUnderlyingNetworkPolicyListenerForTest( - @NonNull IVcnUnderlyingNetworkPolicyListener listener) { - synchronized (mLock) { - addVcnUnderlyingNetworkPolicyListener(listener); - } - } - /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ - @GuardedBy("mLock") @Override public void removeVcnUnderlyingNetworkPolicyListener( @NonNull IVcnUnderlyingNetworkPolicyListener listener) { @@ -1062,8 +1070,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { isVcnManagedNetwork = true; } - final Set restrictedTransports = - mDeps.getRestrictedTransports(subGrp, mLastSnapshot); + final Set restrictedTransports = mDeps.getRestrictedTransports( + subGrp, mLastSnapshot, mConfigs.get(subGrp)); for (int restrictedTransport : restrictedTransports) { if (ncCopy.hasTransport(restrictedTransport)) { if (restrictedTransport == TRANSPORT_CELLULAR) { diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java index 7ac51b7e33..b313c9fc6c 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java @@ -16,7 +16,12 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -24,6 +29,7 @@ import static org.mockito.Mockito.mock; import android.annotation.NonNull; import android.content.Context; import android.os.Parcel; +import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -42,19 +48,36 @@ public class VcnConfigTest { private static final Set GATEWAY_CONNECTION_CONFIGS = Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig()); + private static final Set RESTRICTED_TRANSPORTS = new ArraySet<>(); + + static { + RESTRICTED_TRANSPORTS.add(TRANSPORT_WIFI); + RESTRICTED_TRANSPORTS.add(TRANSPORT_CELLULAR); + } + private final Context mContext = mock(Context.class); // Public visibility for VcnManagementServiceTest - public static VcnConfig buildTestConfig(@NonNull Context context) { + public static VcnConfig buildTestConfig( + @NonNull Context context, Set restrictedTransports) { VcnConfig.Builder builder = new VcnConfig.Builder(context); for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) { builder.addGatewayConnectionConfig(gatewayConnectionConfig); } + if (restrictedTransports != null) { + builder.setRestrictedUnderlyingNetworkTransports(restrictedTransports); + } + return builder.build(); } + // Public visibility for VcnManagementServiceTest + public static VcnConfig buildTestConfig(@NonNull Context context) { + return buildTestConfig(context, null); + } + @Before public void setUp() throws Exception { doReturn(TEST_PACKAGE_NAME).when(mContext).getOpPackageName(); @@ -91,11 +114,25 @@ public class VcnConfigTest { } @Test - public void testBuilderAndGetters() { + public void testBuilderAndGettersDefaultValues() { final VcnConfig config = buildTestConfig(mContext); assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName()); assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs()); + assertFalse(config.isTestModeProfile()); + assertEquals( + Collections.singleton(TRANSPORT_WIFI), + config.getRestrictedUnderlyingNetworkTransports()); + } + + @Test + public void testBuilderAndGettersConfigRestrictedTransports() { + final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS); + + assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName()); + assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs()); + assertFalse(config.isTestModeProfile()); + assertEquals(RESTRICTED_TRANSPORTS, config.getRestrictedUnderlyingNetworkTransports()); } @Test @@ -105,6 +142,24 @@ public class VcnConfigTest { assertEquals(config, new VcnConfig(config.toPersistableBundle())); } + @Test + public void testPersistableBundleWithRestrictedTransports() { + final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS); + + assertEquals(config, new VcnConfig(config.toPersistableBundle())); + } + + @Test + public void testEqualityWithRestrictedTransports() { + final VcnConfig config = buildTestConfig(mContext, RESTRICTED_TRANSPORTS); + final VcnConfig configEqual = buildTestConfig(mContext, RESTRICTED_TRANSPORTS); + final VcnConfig configNotEqual = + buildTestConfig(mContext, Collections.singleton(TRANSPORT_WIFI)); + + assertEquals(config, configEqual); + assertNotEquals(config, configNotEqual); + } + @Test public void testParceling() { final VcnConfig config = buildTestConfig(mContext); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 258642ac22..075bc5e521 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -258,7 +258,7 @@ public class VcnManagementServiceTest { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) - .getRestrictedTransports(any(), any()); + .getRestrictedTransports(any(), any(), any()); } @@ -1038,18 +1038,18 @@ public class VcnManagementServiceTest { new LinkProperties()); } - private void checkGetRestrictedTransports( + private void checkGetRestrictedTransportsFromCarrierConfig( ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot, Set expectedTransports) { Set result = new VcnManagementService.Dependencies() - .getRestrictedTransports(subGrp, lastSnapshot); + .getRestrictedTransportsFromCarrierConfig(subGrp, lastSnapshot); assertEquals(expectedTransports, result); } @Test - public void testGetRestrictedTransports() { + public void testGetRestrictedTransportsFromCarrierConfig() { final Set restrictedTransports = new ArraySet<>(); restrictedTransports.add(TRANSPORT_CELLULAR); restrictedTransports.add(TRANSPORT_WIFI); @@ -1065,11 +1065,12 @@ public class VcnManagementServiceTest { mock(TelephonySubscriptionSnapshot.class); doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); - checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + checkGetRestrictedTransportsFromCarrierConfig( + TEST_UUID_2, lastSnapshot, restrictedTransports); } @Test - public void testGetRestrictedTransports_noRestrictPolicyConfigured() { + public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() { final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI); final PersistableBundleWrapper carrierConfig = @@ -1078,17 +1079,54 @@ public class VcnManagementServiceTest { mock(TelephonySubscriptionSnapshot.class); doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); - checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + checkGetRestrictedTransportsFromCarrierConfig( + TEST_UUID_2, lastSnapshot, restrictedTransports); } @Test - public void testGetRestrictedTransports_noCarrierConfig() { + public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() { final Set restrictedTransports = Collections.singleton(TRANSPORT_WIFI); final TelephonySubscriptionSnapshot lastSnapshot = mock(TelephonySubscriptionSnapshot.class); - checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports); + checkGetRestrictedTransportsFromCarrierConfig( + TEST_UUID_2, lastSnapshot, restrictedTransports); + } + + @Test + public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() { + // Configure restricted transport in CarrierConfig + final Set restrictedTransportInCarrierConfig = + Collections.singleton(TRANSPORT_WIFI); + + PersistableBundle carrierConfigBundle = new PersistableBundle(); + carrierConfigBundle.putIntArray( + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + restrictedTransportInCarrierConfig.stream().mapToInt(i -> i).toArray()); + final PersistableBundleWrapper carrierConfig = + new PersistableBundleWrapper(carrierConfigBundle); + + final TelephonySubscriptionSnapshot lastSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2)); + + // Configure restricted transport in VcnConfig + final Context mockContext = mock(Context.class); + doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName(); + final VcnConfig vcnConfig = + VcnConfigTest.buildTestConfig( + mockContext, Collections.singleton(TRANSPORT_CELLULAR)); + + // Verifications + final Set expectedTransports = new ArraySet<>(); + expectedTransports.add(TRANSPORT_CELLULAR); + expectedTransports.add(TRANSPORT_WIFI); + + Set result = + new VcnManagementService.Dependencies() + .getRestrictedTransports(TEST_UUID_2, lastSnapshot, vcnConfig); + assertEquals(expectedTransports, result); } private void checkGetUnderlyingNetworkPolicy( @@ -1103,7 +1141,7 @@ public class VcnManagementServiceTest { if (isTransportRestricted) { restrictedTransports.add(transportType); } - doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any()); + doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any(), any()); final VcnUnderlyingNetworkPolicy policy = startVcnAndGetPolicyForTransport( @@ -1201,7 +1239,7 @@ public class VcnManagementServiceTest { public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) - .getRestrictedTransports(any(), any()); + .getRestrictedTransports(any(), any(), any()); setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */); @@ -1343,6 +1381,23 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testVcnConfigChangeUpdatesPolicyListener() throws Exception { + setupActiveSubscription(TEST_UUID_2); + + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + final Context mockContext = mock(Context.class); + doReturn(TEST_PACKAGE_NAME).when(mockContext).getOpPackageName(); + final VcnConfig vcnConfig = + VcnConfigTest.buildTestConfig( + mockContext, Collections.singleton(TRANSPORT_CELLULAR)); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME); + + verify(mMockPolicyListener).onPolicyChanged(); + } + @Test public void testRemoveVcnUpdatesPolicyListener() throws Exception { setupActiveSubscription(TEST_UUID_2); @@ -1375,7 +1430,7 @@ public class VcnManagementServiceTest { setupActiveSubscription(TEST_UUID_2); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); - mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); final TelephonySubscriptionSnapshot snapshot = buildSubscriptionSnapshot( From a5d0b94be4bb18f077596349982bb8cb7edb4890 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 10 Dec 2022 01:56:30 +0000 Subject: [PATCH 0348/1057] Expose APIs to configure transports to be restricted by VCN This commit exposes APIs to allow caller to configure transports that willl be marked as restricted by VCN. This API allows carriers to restrict the access to the carrier owned networks and thus prevent apps from circumventing the VCN. Bug: 239104955 Test: make update-api CTS-Coverage-Bug: 262263040 Change-Id: I21aaab57e3d51f4f206c613c94c95ee02150b929 --- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index 8627f5c7a1..dcf002613b 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -25,6 +25,7 @@ import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALI import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.Parcel; import android.os.Parcelable; @@ -158,10 +159,9 @@ public final class VcnConfig implements Parcelable { } /** - * Retrieve the transports that need to be restricted by VCN. + * Retrieve the transports that will be restricted by the VCN. * * @see Builder#setRestrictedUnderlyingNetworkTransports(Set) - * @hide */ @NonNull public Set getRestrictedUnderlyingNetworkTransports() { @@ -306,16 +306,15 @@ public final class VcnConfig implements Parcelable { } /** - * Sets transports that need to be restricted by VCN. + * Sets transports that will be restricted by the VCN. * - * @param transports transports that need to be restricted by VCN. Networks that include any + * @param transports transports that will be restricted by VCN. Networks that include any * of the transports will be marked as restricted. Only {@link * NetworkCapabilities#TRANSPORT_WIFI} and {@link * NetworkCapabilities#TRANSPORT_CELLULAR} are allowed. {@link * NetworkCapabilities#TRANSPORT_WIFI} is marked restricted by default. * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the input contains unsupported transport types. - * @hide */ @NonNull public Builder setRestrictedUnderlyingNetworkTransports(@NonNull Set transports) { From b08897b63c3fb8978c7eaf55746b4b8fb9e22e59 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 6 Dec 2022 02:29:37 +0000 Subject: [PATCH 0349/1057] Add VCN gateway option to enable data stall handling This commit allows caller to enable VCN's ability of handling data stall by setting a VCN gateway option. Bug: 261499808 Test: atest FrameworksVcnTests (new tests), CtsVcnTestCases Change-Id: If37b26faf851153d64face66d10201d7eecad685 --- .../net/vcn/VcnGatewayConnectionConfig.java | 117 +++++++++++++++++- .../vcn/VcnGatewayConnectionConfigTest.java | 87 ++++++++++++- 2 files changed, 198 insertions(+), 6 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 2339656979..7718053ddf 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -42,6 +42,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -130,6 +131,33 @@ public final class VcnGatewayConnectionConfig { }) public @interface VcnSupportedCapability {} + /** + * Perform mobility update to attempt recovery from suspected data stalls. + * + *

    If set, the gatway connection will monitor the data stall detection of the VCN network. + * When there is a suspected data stall, the gateway connection will attempt recovery by + * performing a mobility update on the underlying IKE session. + * + * @hide + */ + public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"VCN_GATEWAY_OPTION_"}, + value = { + // TODO: b/261499808 Add VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY + // when it is exposed + }) + public @interface VcnGatewayOption {} + + private static final Set ALLOWED_GATEWAY_OPTIONS = new ArraySet<>(); + + static { + ALLOWED_GATEWAY_OPTIONS.add(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); + } + private static final int DEFAULT_MAX_MTU = 1500; /** @@ -201,6 +229,9 @@ public final class VcnGatewayConnectionConfig { private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; @NonNull private final long[] mRetryIntervalsMs; + private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; + @NonNull private final Set mGatewayOptions; + /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, @@ -208,12 +239,14 @@ public final class VcnGatewayConnectionConfig { @NonNull Set exposedCapabilities, @NonNull List underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, - @IntRange(from = MIN_MTU_V6) int maxMtu) { + @IntRange(from = MIN_MTU_V6) int maxMtu, + @NonNull Set gatewayOptions) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; + mGatewayOptions = Collections.unmodifiableSet(new HashSet(gatewayOptions)); mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); if (mUnderlyingNetworkTemplates.isEmpty()) { @@ -256,6 +289,20 @@ public final class VcnGatewayConnectionConfig { VcnUnderlyingNetworkTemplate::fromPersistableBundle); } + final PersistableBundle gatewayOptionsBundle = in.getPersistableBundle(GATEWAY_OPTIONS_KEY); + + if (gatewayOptionsBundle == null) { + // GATEWAY_OPTIONS_KEY was added in Android U. Thus VcnGatewayConnectionConfig created + // on old platforms will not have this data and will be assigned with the default value + mGatewayOptions = Collections.emptySet(); + } else { + mGatewayOptions = + new HashSet<>( + PersistableBundleUtils.toList( + gatewayOptionsBundle, + PersistableBundleUtils.INTEGER_DESERIALIZER)); + } + mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -279,6 +326,10 @@ public final class VcnGatewayConnectionConfig { Preconditions.checkArgument( mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + + for (int option : mGatewayOptions) { + validateGatewayOption(option); + } } private static void checkValidCapability(int capability) { @@ -315,6 +366,12 @@ public final class VcnGatewayConnectionConfig { } } + private static void validateGatewayOption(int option) { + if (!ALLOWED_GATEWAY_OPTIONS.contains(option)) { + throw new IllegalArgumentException("Invalid vcn gateway option: " + option); + } + } + /** * Returns the configured Gateway Connection name. * @@ -398,6 +455,18 @@ public final class VcnGatewayConnectionConfig { return mMaxMtu; } + /** + * Checks if the given VCN gateway option is enabled. + * + * @param option the option to check. + * @throws IllegalArgumentException if the provided option is invalid. + * @hide + */ + public boolean hasGatewayOption(@VcnGatewayOption int option) { + validateGatewayOption(option); + return mGatewayOptions.contains(option); + } + /** * Converts this config to a PersistableBundle. * @@ -418,11 +487,16 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( mUnderlyingNetworkTemplates, VcnUnderlyingNetworkTemplate::toPersistableBundle); + final PersistableBundle gatewayOptionsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mGatewayOptions), + PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle); + result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -437,7 +511,8 @@ public final class VcnGatewayConnectionConfig { mExposedCapabilities, mUnderlyingNetworkTemplates, Arrays.hashCode(mRetryIntervalsMs), - mMaxMtu); + mMaxMtu, + mGatewayOptions); } @Override @@ -452,7 +527,8 @@ public final class VcnGatewayConnectionConfig { && mExposedCapabilities.equals(rhs.mExposedCapabilities) && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) - && mMaxMtu == rhs.mMaxMtu; + && mMaxMtu == rhs.mMaxMtu + && mGatewayOptions.equals(rhs.mGatewayOptions); } /** @@ -470,6 +546,8 @@ public final class VcnGatewayConnectionConfig { @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; + @NonNull private final Set mGatewayOptions = new ArraySet<>(); + // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent. // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS // when on Cell. @@ -627,6 +705,36 @@ public final class VcnGatewayConnectionConfig { return this; } + /** + * Enables the specified VCN gateway option. + * + * @param option the option to be enabled + * @return this {@link Builder} instance, for chaining + * @throws IllegalArgumentException if the provided option is invalid + * @hide + */ + @NonNull + public Builder addGatewayOption(@VcnGatewayOption int option) { + validateGatewayOption(option); + mGatewayOptions.add(option); + return this; + } + + /** + * Resets (disables) the specified VCN gateway option. + * + * @param option the option to be disabled + * @return this {@link Builder} instance, for chaining + * @throws IllegalArgumentException if the provided option is invalid + * @hide + */ + @NonNull + public Builder removeGatewayOption(@VcnGatewayOption int option) { + validateGatewayOption(option); + mGatewayOptions.remove(option); + return this; + } + /** * Builds and validates the VcnGatewayConnectionConfig. * @@ -640,7 +748,8 @@ public final class VcnGatewayConnectionConfig { mExposedCapabilities, mUnderlyingNetworkTemplates, mRetryIntervalsMs, - mMaxMtu); + mMaxMtu, + mGatewayOptions); } } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 2aef9ae7ca..de84657907 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -19,9 +19,11 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES; import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_TEMPLATES_KEY; +import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; @@ -42,7 +44,9 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -79,6 +83,9 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; + private static final Set GATEWAY_OPTIONS = + Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); + public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS = TunnelConnectionParamsUtilsTest.buildTestParams(); @@ -109,10 +116,16 @@ public class VcnGatewayConnectionConfigTest { TUNNEL_CONNECTION_PARAMS); } - private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps( - VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) { + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions( + VcnGatewayConnectionConfig.Builder builder, + Set gatewayOptions, + int... exposedCaps) { builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + for (int option : gatewayOptions) { + builder.addGatewayOption(option); + } + for (int caps : exposedCaps) { builder.addExposedCapability(caps); } @@ -120,11 +133,27 @@ public class VcnGatewayConnectionConfigTest { return builder.build(); } + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps( + VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) { + return buildTestConfigWithExposedCapsAndOptions( + builder, Collections.emptySet(), exposedCaps); + } + // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps); } + private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions( + VcnGatewayConnectionConfig.Builder builder, Set gatewayOptions) { + return buildTestConfigWithExposedCapsAndOptions(builder, gatewayOptions, EXPOSED_CAPS); + } + + private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions( + Set gatewayOptions) { + return buildTestConfigWithExposedCapsAndOptions(newBuilder(), gatewayOptions, EXPOSED_CAPS); + } + @Test public void testBuilderRequiresNonNullGatewayConnectionName() { try { @@ -210,6 +239,15 @@ public class VcnGatewayConnectionConfigTest { } } + @Test + public void testBuilderRequiresValidOption() { + try { + newBuilder().addGatewayOption(-1); + fail("Expected exception due to the invalid VCN gateway option"); + } catch (IllegalArgumentException e) { + } + } + @Test public void testBuilderAndGetters() { final VcnGatewayConnectionConfig config = buildTestConfig(); @@ -225,6 +263,20 @@ public class VcnGatewayConnectionConfigTest { assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); + + assertFalse( + config.hasGatewayOption( + VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY)); + } + + @Test + public void testBuilderAndGettersWithOptions() { + final VcnGatewayConnectionConfig config = + buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS); + + for (int option : GATEWAY_OPTIONS) { + assertTrue(config.hasGatewayOption(option)); + } } @Test @@ -234,6 +286,14 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } + @Test + public void testPersistableBundleWithOptions() { + final VcnGatewayConnectionConfig config = + buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS); + + assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); + } + @Test public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() { PersistableBundle configBundle = buildTestConfig().toPersistableBundle(); @@ -318,4 +378,27 @@ public class VcnGatewayConnectionConfigTest { assertNotEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesNotEqual); assertNotEquals(config, configNotEqual); } + + private static VcnGatewayConnectionConfig buildConfigWithGatewayOptionsForEqualityTest( + Set gatewayOptions) { + return buildTestConfigWithGatewayOptions( + new VcnGatewayConnectionConfig.Builder( + "buildConfigWithGatewayOptionsForEqualityTest", TUNNEL_CONNECTION_PARAMS), + gatewayOptions); + } + + @Test + public void testVcnGatewayOptionsEquality() throws Exception { + final VcnGatewayConnectionConfig config = + buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS); + + final VcnGatewayConnectionConfig configEqual = + buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS); + + final VcnGatewayConnectionConfig configNotEqual = + buildConfigWithGatewayOptionsForEqualityTest(Collections.emptySet()); + + assertEquals(config, configEqual); + assertNotEquals(config, configNotEqual); + } } From d95d4fc55e0716558555137406c59556d4efa7f4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 1 Dec 2022 02:09:09 +0000 Subject: [PATCH 0350/1057] Perform MOBIKE when data stall is suspected on VCN network This commit updates VCN to listen to the connectivity diagnostics callback so that when there is a suspected data stall VCN will call into IKE to perform MOBIKE to recover. Bug: 261499808 Test: atest FrameworksVcnTests (new tests), CtsVcnTestCases Change-Id: Ic8ec45870b7e5190db4fe6b8b7710f54e7fb61f4 --- .../server/vcn/VcnGatewayConnection.java | 93 ++++++++++++++++++- .../vcn/VcnGatewayConnectionConfigTest.java | 3 +- ...cnGatewayConnectionConnectedStateTest.java | 58 ++++++++++++ .../server/vcn/VcnGatewayConnectionTest.java | 66 ++++++++++++- .../vcn/VcnGatewayConnectionTestBase.java | 9 ++ 5 files changed, 226 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 05df22f124..3be16a1fec 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -26,6 +26,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; +import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; @@ -36,6 +37,8 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.ConnectivityDiagnosticsManager; +import android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpPrefix; @@ -50,6 +53,7 @@ import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; +import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; @@ -546,6 +550,39 @@ public class VcnGatewayConnection extends StateMachine { } } + /** + * Sent when there is a suspected data stall on a network + * + *

    Only relevant in the Connected state. + * + * @param arg1 The "all" token; this signal is always honored. + * @param obj @NonNull An EventDataStallSuspectedInfo instance with relevant data. + */ + private static final int EVENT_DATA_STALL_SUSPECTED = 13; + + private static class EventDataStallSuspectedInfo implements EventInfo { + @NonNull public final Network network; + + EventDataStallSuspectedInfo(@NonNull Network network) { + this.network = network; + } + + @Override + public int hashCode() { + return Objects.hash(network); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventDataStallSuspectedInfo)) { + return false; + } + + final EventDataStallSuspectedInfo rhs = (EventDataStallSuspectedInfo) other; + return Objects.equals(network, rhs.network); + } + } + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -578,10 +615,13 @@ public class VcnGatewayConnection extends StateMachine { @NonNull private final VcnUnderlyingNetworkControllerCallback mUnderlyingNetworkControllerCallback; + @NonNull private final VcnConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback; + private final boolean mIsMobileDataEnabled; @NonNull private final IpSecManager mIpSecManager; @NonNull private final ConnectivityManager mConnectivityManager; + @NonNull private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager; @Nullable private IpSecTunnelInterface mTunnelIface = null; @@ -748,6 +788,20 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkControllerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); + mConnectivityDiagnosticsManager = + mVcnContext.getContext().getSystemService(ConnectivityDiagnosticsManager.class); + + mConnectivityDiagnosticsCallback = new VcnConnectivityDiagnosticsCallback(); + + if (mConnectionConfig.hasGatewayOption( + VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY)) { + final NetworkRequest diagRequest = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + mConnectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback( + diagRequest, + new HandlerExecutor(new Handler(vcnContext.getLooper())), + mConnectivityDiagnosticsCallback); + } addState(mDisconnectedState); addState(mDisconnectingState); @@ -810,6 +864,9 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkController.teardown(); mGatewayStatusCallback.onQuit(); + + mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback); } /** @@ -828,6 +885,20 @@ public class VcnGatewayConnection extends StateMachine { sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL); } + private class VcnConnectivityDiagnosticsCallback extends ConnectivityDiagnosticsCallback { + @Override + public void onDataStallSuspected(ConnectivityDiagnosticsManager.DataStallReport report) { + mVcnContext.ensureRunningOnLooperThread(); + + final Network network = report.getNetwork(); + logInfo("Data stall suspected on " + network); + sendMessageAndAcquireWakeLock( + EVENT_DATA_STALL_SUSPECTED, + TOKEN_ALL, + new EventDataStallSuspectedInfo(network)); + } + } + private class VcnUnderlyingNetworkControllerCallback implements UnderlyingNetworkControllerCallback { @Override @@ -1367,7 +1438,8 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough case EVENT_MIGRATION_COMPLETED: // Fallthrough - case EVENT_IKE_CONNECTION_INFO_CHANGED: + case EVENT_IKE_CONNECTION_INFO_CHANGED: // Fallthrough + case EVENT_DATA_STALL_SUSPECTED: logUnexpectedEvent(msg.what); break; default: @@ -1925,6 +1997,11 @@ public class VcnGatewayConnection extends StateMachine { mIkeConnectionInfo = ((EventIkeConnectionInfoChangedInfo) msg.obj).ikeConnectionInfo; break; + case EVENT_DATA_STALL_SUSPECTED: + final Network networkWithDataStall = + ((EventDataStallSuspectedInfo) msg.obj).network; + handleDataStallSuspected(networkWithDataStall); + break; default: logUnhandledMessage(msg); break; @@ -1985,6 +2062,15 @@ public class VcnGatewayConnection extends StateMachine { } } + private void handleDataStallSuspected(Network networkWithDataStall) { + if (mUnderlying != null + && mNetworkAgent != null + && mNetworkAgent.getNetwork().equals(networkWithDataStall)) { + logInfo("Perform Mobility update to recover from suspected data stall"); + mIkeSession.setNetwork(mUnderlying.network); + } + } + protected void setupInterfaceAndNetworkAgent( int token, @NonNull IpSecTunnelInterface tunnelIface, @@ -2423,6 +2509,11 @@ public class VcnGatewayConnection extends StateMachine { return mUnderlyingNetworkControllerCallback; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + ConnectivityDiagnosticsCallback getConnectivityDiagnosticsCallback() { + return mConnectivityDiagnosticsCallback; + } + @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkRecord getUnderlyingNetwork() { return mUnderlying; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index de84657907..40408880a2 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -149,7 +149,8 @@ public class VcnGatewayConnectionConfigTest { return buildTestConfigWithExposedCapsAndOptions(builder, gatewayOptions, EXPOSED_CAPS); } - private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions( + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions( Set gatewayOptions) { return buildTestConfigWithExposedCapsAndOptions(newBuilder(), gatewayOptions, EXPOSED_CAPS); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 15d4f10971..1c21a067bd 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -50,9 +50,11 @@ import static org.mockito.Mockito.when; import static java.util.Collections.singletonList; +import android.net.ConnectivityDiagnosticsManager.DataStallReport; import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; @@ -63,10 +65,12 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; +import android.os.PersistableBundle; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import com.android.server.vcn.util.MtuUtils; import org.junit.Before; @@ -88,6 +92,7 @@ import java.util.function.Consumer; public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { private VcnIkeSession mIkeSession; private VcnNetworkAgent mNetworkAgent; + private Network mVcnNetwork; @Before public void setUp() throws Exception { @@ -98,6 +103,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .when(mDeps) .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any()); + mVcnNetwork = mock(Network.class); + doReturn(mVcnNetwork).when(mNetworkAgent).getNetwork(); + mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); @@ -166,6 +174,56 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } + private void verifyDataStallTriggersMigration( + UnderlyingNetworkRecord networkRecord, + Network networkWithDataStall, + boolean expectMobilityUpdate) + throws Exception { + mGatewayConnection.setUnderlyingNetwork(networkRecord); + triggerChildOpened(); + mTestLooper.dispatchAll(); + + final DataStallReport report = + new DataStallReport( + networkWithDataStall, + 1234 /* reportTimestamp */, + 1 /* detectionMethod */, + new LinkProperties(), + new NetworkCapabilities(), + new PersistableBundle()); + + mGatewayConnection.getConnectivityDiagnosticsCallback().onDataStallSuspected(report); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + + if (expectMobilityUpdate) { + verify(mIkeSession).setNetwork(networkRecord.network); + } else { + verify(mIkeSession, never()).setNetwork(any(Network.class)); + } + } + + @Test + public void testDataStallTriggersMigration() throws Exception { + verifyDataStallTriggersMigration( + TEST_UNDERLYING_NETWORK_RECORD_1, mVcnNetwork, true /* expectMobilityUpdate */); + } + + @Test + public void testDataStallWontTriggerMigrationWhenOnOtherNetwork() throws Exception { + verifyDataStallTriggersMigration( + TEST_UNDERLYING_NETWORK_RECORD_1, + mock(Network.class), + false /* expectMobilityUpdate */); + } + + @Test + public void testDataStallWontTriggerMigrationWhenUnderlyingNetworkLost() throws Exception { + verifyDataStallTriggersMigration( + null /* networkRecord */, mock(Network.class), false /* expectMobilityUpdate */); + } + private void verifyVcnTransformsApplied( VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform) throws Exception { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 6a9a1e22ca..a4ee2de9f4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -24,6 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; @@ -34,20 +35,25 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import android.net.IpSecManager; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; @@ -64,6 +70,7 @@ import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.net.InetAddress; import java.util.Arrays; @@ -71,7 +78,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.Executor; /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @@ -287,5 +296,60 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verify(vcnNetworkAgent).unregister(); verifyWakeLockReleased(); + + verify(mConnDiagMgr) + .unregisterConnectivityDiagnosticsCallback( + mGatewayConnection.getConnectivityDiagnosticsCallback()); + } + + private VcnGatewayConnection buildConnectionWithDataStallHandling( + boolean datatStallHandlingEnabled) throws Exception { + Set options = + datatStallHandlingEnabled + ? Collections.singleton( + VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY) + : Collections.emptySet(); + final VcnGatewayConnectionConfig gatewayConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithGatewayOptions(options); + final VcnGatewayConnection gatewayConnection = + new VcnGatewayConnection( + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + gatewayConfig, + mGatewayStatusCallback, + true /* isMobileDataEnabled */, + mDeps); + return gatewayConnection; + } + + @Test + public void testDataStallHandlingEnabled() throws Exception { + final VcnGatewayConnection gatewayConnection = + buildConnectionWithDataStallHandling(true /* datatStallHandlingEnabled */); + + final ArgumentCaptor networkRequestCaptor = + ArgumentCaptor.forClass(NetworkRequest.class); + verify(mConnDiagMgr) + .registerConnectivityDiagnosticsCallback( + networkRequestCaptor.capture(), + any(Executor.class), + eq(gatewayConnection.getConnectivityDiagnosticsCallback())); + + final NetworkRequest nr = networkRequestCaptor.getValue(); + final NetworkRequest expected = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); + assertEquals(expected, nr); + } + + @Test + public void testDataStallHandlingDisabled() throws Exception { + buildConnectionWithDataStallHandling(false /* datatStallHandlingEnabled */); + + verify(mConnDiagMgr, never()) + .registerConnectivityDiagnosticsCallback( + any(NetworkRequest.class), + any(Executor.class), + any(ConnectivityDiagnosticsCallback.class)); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 785bff167a..7bafd24379 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpSecConfig; @@ -157,6 +158,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; + @NonNull protected final ConnectivityDiagnosticsManager mConnDiagMgr; @NonNull protected final IkeSessionConnectionInfo mIkeConnectionInfo; @NonNull protected final IkeSessionConfiguration mIkeSessionConfiguration; @@ -186,6 +188,13 @@ public class VcnGatewayConnectionTestBase { VcnTestUtils.setupSystemService( mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + mConnDiagMgr = mock(ConnectivityDiagnosticsManager.class); + VcnTestUtils.setupSystemService( + mContext, + mConnDiagMgr, + Context.CONNECTIVITY_DIAGNOSTICS_SERVICE, + ConnectivityDiagnosticsManager.class); + mIkeConnectionInfo = new IkeSessionConnectionInfo(TEST_ADDR, TEST_ADDR_2, mock(Network.class)); mIkeSessionConfiguration = new IkeSessionConfiguration.Builder(mIkeConnectionInfo).build(); From 5372ce5a9795e5299c5ccb4ad0985b69a6c9a191 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 12 Dec 2022 23:38:39 +0000 Subject: [PATCH 0351/1057] APIs to enable data stall handling in VCN This commit expose APIs to set VCN Gateway Options for additional VCN abilities, and the option to allow VCN to detect suspected data stall and recover with IKE mobility update. Bug: 261499808 Test: make update-api && make API-Coverage-Bug: 262297702 Change-Id: If8097d587e7099e9bb9a43328dad3cac3cfb9703 --- .../android/net/vcn/VcnGatewayConnectionConfig.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 7718053ddf..b8850f427c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -137,8 +137,6 @@ public final class VcnGatewayConnectionConfig { *

    If set, the gatway connection will monitor the data stall detection of the VCN network. * When there is a suspected data stall, the gateway connection will attempt recovery by * performing a mobility update on the underlying IKE session. - * - * @hide */ public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; @@ -147,8 +145,7 @@ public final class VcnGatewayConnectionConfig { @IntDef( prefix = {"VCN_GATEWAY_OPTION_"}, value = { - // TODO: b/261499808 Add VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY - // when it is exposed + VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY, }) public @interface VcnGatewayOption {} @@ -460,7 +457,8 @@ public final class VcnGatewayConnectionConfig { * * @param option the option to check. * @throws IllegalArgumentException if the provided option is invalid. - * @hide + * @see Builder#addGatewayOption(int) + * @see Builder#removeGatewayOption(int) */ public boolean hasGatewayOption(@VcnGatewayOption int option) { validateGatewayOption(option); @@ -711,7 +709,6 @@ public final class VcnGatewayConnectionConfig { * @param option the option to be enabled * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the provided option is invalid - * @hide */ @NonNull public Builder addGatewayOption(@VcnGatewayOption int option) { @@ -726,7 +723,6 @@ public final class VcnGatewayConnectionConfig { * @param option the option to be disabled * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the provided option is invalid - * @hide */ @NonNull public Builder removeGatewayOption(@VcnGatewayOption int option) { From d6bc3469404b130bb33f5e0fa1fe2002f89ca191 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 14 Dec 2022 18:42:55 +0000 Subject: [PATCH 0352/1057] Fix a typo and use ArraySet in VCN This is a cleanup commit to fix typos and switch to use ArraySet instead of HashSet for better performance. Bug: 261499808 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: Ie4a83ab22aa2b3682856776b762b4356b13b4745 --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index b8850f427c..4c9d150ec4 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -42,7 +42,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -134,7 +133,7 @@ public final class VcnGatewayConnectionConfig { /** * Perform mobility update to attempt recovery from suspected data stalls. * - *

    If set, the gatway connection will monitor the data stall detection of the VCN network. + *

    If set, the gateway connection will monitor the data stall detection of the VCN network. * When there is a suspected data stall, the gateway connection will attempt recovery by * performing a mobility update on the underlying IKE session. */ @@ -243,7 +242,7 @@ public final class VcnGatewayConnectionConfig { mExposedCapabilities = new TreeSet(exposedCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; - mGatewayOptions = Collections.unmodifiableSet(new HashSet(gatewayOptions)); + mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); if (mUnderlyingNetworkTemplates.isEmpty()) { @@ -294,7 +293,7 @@ public final class VcnGatewayConnectionConfig { mGatewayOptions = Collections.emptySet(); } else { mGatewayOptions = - new HashSet<>( + new ArraySet<>( PersistableBundleUtils.toList( gatewayOptionsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); From 455f7764645c49d39f68fcf9c92455638365be2d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 28 Nov 2022 23:49:02 +0000 Subject: [PATCH 0353/1057] Support configuring capabilities in VCN cell network template This commit adds the support of configuring required and forbidden capabilities in the VCN cell underlying network matching template so that a cell network MUST match the capability criteria to be selected as the VCN's underlying network. Bug: 245618320 Test: FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I3ed65ae86e0078fb5f0f6ab311fbc46f915ecdab --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 275 +++++++++++++++++- .../VcnCellUnderlyingNetworkTemplateTest.java | 76 ++++- 2 files changed, 342 insertions(+), 9 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 2d1a3fe8e9..35f5e9e47f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -15,6 +15,12 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.getMatchCriteriaString; @@ -37,10 +43,13 @@ import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -64,6 +73,23 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork private static final int DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA = MATCH_ANY; private final int mOpportunisticMatchCriteria; + private static final String CAPABILITIES_MATCH_CRITERIA_KEY = "mCapabilitiesMatchCriteria"; + @NonNull private final Map mCapabilitiesMatchCriteria; + + private static final Map CAPABILITIES_MATCH_CRITERIA_DEFAULT; + + static { + Map capsMatchCriteria = new HashMap<>(); + capsMatchCriteria.put(NET_CAPABILITY_CBS, MATCH_ANY); + capsMatchCriteria.put(NET_CAPABILITY_DUN, MATCH_ANY); + capsMatchCriteria.put(NET_CAPABILITY_IMS, MATCH_ANY); + capsMatchCriteria.put(NET_CAPABILITY_INTERNET, MATCH_REQUIRED); + capsMatchCriteria.put(NET_CAPABILITY_MMS, MATCH_ANY); + capsMatchCriteria.put(NET_CAPABILITY_RCS, MATCH_ANY); + + CAPABILITIES_MATCH_CRITERIA_DEFAULT = Collections.unmodifiableMap(capsMatchCriteria); + } + private VcnCellUnderlyingNetworkTemplate( int meteredMatchCriteria, int minEntryUpstreamBandwidthKbps, @@ -73,7 +99,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork Set allowedNetworkPlmnIds, Set allowedSpecificCarrierIds, int roamingMatchCriteria, - int opportunisticMatchCriteria) { + int opportunisticMatchCriteria, + Map capabilitiesMatchCriteria) { super( NETWORK_PRIORITY_TYPE_CELL, meteredMatchCriteria, @@ -85,6 +112,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds); mRoamingMatchCriteria = roamingMatchCriteria; mOpportunisticMatchCriteria = opportunisticMatchCriteria; + mCapabilitiesMatchCriteria = new HashMap<>(capabilitiesMatchCriteria); validate(); } @@ -94,6 +122,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork protected void validate() { super.validate(); validatePlmnIds(mAllowedNetworkPlmnIds); + validateCapabilitiesMatchCriteria(mCapabilitiesMatchCriteria); Objects.requireNonNull(mAllowedSpecificCarrierIds, "matchingCarrierIds is null"); validateMatchCriteria(mRoamingMatchCriteria, "mRoamingMatchCriteria"); validateMatchCriteria(mOpportunisticMatchCriteria, "mOpportunisticMatchCriteria"); @@ -113,6 +142,28 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } } + private static void validateCapabilitiesMatchCriteria( + Map capabilitiesMatchCriteria) { + Objects.requireNonNull(capabilitiesMatchCriteria, "capabilitiesMatchCriteria is null"); + + boolean requiredCapabilityFound = false; + for (Map.Entry entry : capabilitiesMatchCriteria.entrySet()) { + final int capability = entry.getKey(); + final int matchCriteria = entry.getValue(); + + Preconditions.checkArgument( + CAPABILITIES_MATCH_CRITERIA_DEFAULT.containsKey(capability), + "NetworkCapability " + capability + "out of range"); + validateMatchCriteria(matchCriteria, "capability " + capability); + + requiredCapabilityFound |= (matchCriteria == MATCH_REQUIRED); + } + + if (!requiredCapabilityFound) { + throw new IllegalArgumentException("No required capabilities found"); + } + } + /** @hide */ @NonNull @VisibleForTesting(visibility = Visibility.PROTECTED) @@ -146,6 +197,19 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork PersistableBundleUtils.toList( specificCarrierIdsBundle, INTEGER_DESERIALIZER)); + final PersistableBundle capabilitiesMatchCriteriaBundle = + in.getPersistableBundle(CAPABILITIES_MATCH_CRITERIA_KEY); + final Map capabilitiesMatchCriteria; + if (capabilitiesMatchCriteriaBundle == null) { + capabilitiesMatchCriteria = CAPABILITIES_MATCH_CRITERIA_DEFAULT; + } else { + capabilitiesMatchCriteria = + PersistableBundleUtils.toMap( + capabilitiesMatchCriteriaBundle, + INTEGER_DESERIALIZER, + INTEGER_DESERIALIZER); + } + final int roamingMatchCriteria = in.getInt(ROAMING_MATCH_KEY); final int opportunisticMatchCriteria = in.getInt(OPPORTUNISTIC_MATCH_KEY); @@ -158,7 +222,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork allowedNetworkPlmnIds, allowedSpecificCarrierIds, roamingMatchCriteria, - opportunisticMatchCriteria); + opportunisticMatchCriteria, + capabilitiesMatchCriteria); } /** @hide */ @@ -178,6 +243,12 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER); result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle); + final PersistableBundle capabilitiesMatchCriteriaBundle = + PersistableBundleUtils.fromMap( + mCapabilitiesMatchCriteria, INTEGER_SERIALIZER, INTEGER_SERIALIZER); + result.putPersistableBundle( + CAPABILITIES_MATCH_CRITERIA_KEY, capabilitiesMatchCriteriaBundle); + result.putInt(ROAMING_MATCH_KEY, mRoamingMatchCriteria); result.putInt(OPPORTUNISTIC_MATCH_KEY, mOpportunisticMatchCriteria); @@ -225,12 +296,76 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return mOpportunisticMatchCriteria; } + /** + * Returns the matching criteria for CBS networks. + * + * @see Builder#setCbs(int) + * @hide + */ + @MatchCriteria + public int getCbs() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_CBS); + } + + /** + * Returns the matching criteria for DUN networks. + * + * @see Builder#setDun(int) + * @hide + */ + @MatchCriteria + public int getDun() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_DUN); + } + /** + * Returns the matching criteria for IMS networks. + * + * @see Builder#setIms(int) + * @hide + */ + @MatchCriteria + public int getIms() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_IMS); + } + /** + * Returns the matching criteria for INTERNET networks. + * + * @see Builder#setInternet(int) + * @hide + */ + @MatchCriteria + public int getInternet() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_INTERNET); + } + /** + * Returns the matching criteria for MMS networks. + * + * @see Builder#setMms(int) + * @hide + */ + @MatchCriteria + public int getMms() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_MMS); + } + + /** + * Returns the matching criteria for RCS networks. + * + * @see Builder#setRcs(int) + * @hide + */ + @MatchCriteria + public int getRcs() { + return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_RCS); + } + @Override public int hashCode() { return Objects.hash( super.hashCode(), mAllowedNetworkPlmnIds, mAllowedSpecificCarrierIds, + mCapabilitiesMatchCriteria, mRoamingMatchCriteria, mOpportunisticMatchCriteria); } @@ -248,6 +383,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork final VcnCellUnderlyingNetworkTemplate rhs = (VcnCellUnderlyingNetworkTemplate) other; return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds) && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds) + && Objects.equals(mCapabilitiesMatchCriteria, rhs.mCapabilitiesMatchCriteria) && mRoamingMatchCriteria == rhs.mRoamingMatchCriteria && mOpportunisticMatchCriteria == rhs.mOpportunisticMatchCriteria; } @@ -261,6 +397,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork if (!mAllowedNetworkPlmnIds.isEmpty()) { pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds); } + pw.println("mCapabilitiesMatchCriteria: " + mCapabilitiesMatchCriteria); if (mRoamingMatchCriteria != DEFAULT_ROAMING_MATCH_CRITERIA) { pw.println("mRoamingMatchCriteria: " + getMatchCriteriaString(mRoamingMatchCriteria)); } @@ -277,6 +414,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @NonNull private final Set mAllowedNetworkPlmnIds = new ArraySet<>(); @NonNull private final Set mAllowedSpecificCarrierIds = new ArraySet<>(); + @NonNull private final Map mCapabilitiesMatchCriteria = new HashMap<>(); private int mRoamingMatchCriteria = DEFAULT_ROAMING_MATCH_CRITERIA; private int mOpportunisticMatchCriteria = DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA; @@ -287,7 +425,9 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; /** Construct a Builder object. */ - public Builder() {} + public Builder() { + mCapabilitiesMatchCriteria.putAll(CAPABILITIES_MATCH_CRITERIA_DEFAULT); + } /** * Set the matching criteria for metered networks. @@ -461,6 +601,132 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return this; } + /** + * Sets the matching criteria for CBS networks. + * + *

    A template where {@code setCbs(MATCH_REQUIRED)} is called will only match CBS networks + * (ones with NET_CAPABILITY_CBS). A template where {@code setCbs(MATCH_FORBIDDEN)} is + * called will only match networks that do not support CBS (ones without + * NET_CAPABILITY_CBS). + * + * @param matchCriteria the matching criteria for CBS networks. Defaults to {@link + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_CBS + * @hide + */ + @NonNull + public Builder setCbs(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setCbs"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_CBS, matchCriteria); + return this; + } + + /** + * Sets the matching criteria for DUN networks. + * + *

    A template where {@code setDun(MATCH_REQUIRED)} is called will only match DUN networks + * (ones with NET_CAPABILITY_DUN). A template where {@code setDun(MATCH_FORBIDDEN)} is + * called will only match networks that do not support DUN (ones without + * NET_CAPABILITY_DUN). + * + * @param matchCriteria the matching criteria for DUN networks. Defaults to {@link + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_DUN + * @hide + */ + @NonNull + public Builder setDun(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setDun"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_DUN, matchCriteria); + return this; + } + + /** + * Sets the matching criteria for IMS networks. + * + *

    A template where {@code setIms(MATCH_REQUIRED)} is called will only match IMS networks + * (ones with NET_CAPABILITY_IMS). A template where {@code setIms(MATCH_FORBIDDEN)} is + * called will only match networks that do not support IMS (ones without + * NET_CAPABILITY_IMS). + * + * @param matchCriteria the matching criteria for IMS networks. Defaults to {@link + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_IMS + * @hide + */ + @NonNull + public Builder setIms(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setIms"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_IMS, matchCriteria); + return this; + } + + /** + * Sets the matching criteria for INTERNET networks. + * + *

    A template where {@code setInternet(MATCH_REQUIRED)} is called will only match + * INTERNET networks (ones with NET_CAPABILITY_INTERNET). A template where {@code + * setInternet(MATCH_FORBIDDEN)} is called will only match networks that do not support + * INTERNET (ones without NET_CAPABILITY_INTERNET). + * + * @param matchCriteria the matching criteria for INTERNET networks. Defaults to {@link + * #MATCH_REQUIRED}. + * @see NetworkCapabilities#NET_CAPABILITY_INTERNET + * @hide + */ + @NonNull + public Builder setInternet(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setInternet"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_INTERNET, matchCriteria); + return this; + } + + /** + * Sets the matching criteria for MMS networks. + * + *

    A template where {@code setMms(MATCH_REQUIRED)} is called will only match MMS networks + * (ones with NET_CAPABILITY_MMS). A template where {@code setMms(MATCH_FORBIDDEN)} is + * called will only match networks that do not support MMS (ones without + * NET_CAPABILITY_MMS). + * + * @param matchCriteria the matching criteria for MMS networks. Defaults to {@link + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_MMS + * @hide + */ + @NonNull + public Builder setMms(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setMms"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_MMS, matchCriteria); + return this; + } + + /** + * Sets the matching criteria for RCS networks. + * + *

    A template where {@code setRcs(MATCH_REQUIRED)} is called will only match RCS networks + * (ones with NET_CAPABILITY_RCS). A template where {@code setRcs(MATCH_FORBIDDEN)} is + * called will only match networks that do not support RCS (ones without + * NET_CAPABILITY_RCS). + * + * @param matchCriteria the matching criteria for RCS networks. Defaults to {@link + * #MATCH_ANY}. + * @see NetworkCapabilities#NET_CAPABILITY_RCS + * @hide + */ + @NonNull + public Builder setRcs(@MatchCriteria int matchCriteria) { + validateMatchCriteria(matchCriteria, "setRcs"); + + mCapabilitiesMatchCriteria.put(NET_CAPABILITY_RCS, matchCriteria); + return this; + } + /** Build the VcnCellUnderlyingNetworkTemplate. */ @NonNull public VcnCellUnderlyingNetworkTemplate build() { @@ -473,7 +739,8 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork mAllowedNetworkPlmnIds, mAllowedSpecificCarrierIds, mRoamingMatchCriteria, - mOpportunisticMatchCriteria); + mOpportunisticMatchCriteria, + mCapabilitiesMatchCriteria); } } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index 2fbcf9d87b..1f6bb21506 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -20,6 +20,7 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; import org.junit.Test; @@ -31,8 +32,7 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); - // Package private for use in VcnGatewayConnectionConfigTest - static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { + private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() { return new VcnCellUnderlyingNetworkTemplate.Builder() .setMetered(MATCH_FORBIDDEN) .setMinUpstreamBandwidthKbps( @@ -44,13 +44,44 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe .setOperatorPlmnIds(ALLOWED_PLMN_IDS) .setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS) .setRoaming(MATCH_FORBIDDEN) - .setOpportunistic(MATCH_REQUIRED) - .build(); + .setOpportunistic(MATCH_REQUIRED); + } + + // Package private for use in VcnGatewayConnectionConfigTest + static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { + return getTestNetworkTemplateBuilder().build(); + } + + private void setAllCapabilities( + VcnCellUnderlyingNetworkTemplate.Builder builder, int matchCriteria) { + builder.setCbs(matchCriteria); + builder.setDun(matchCriteria); + builder.setIms(matchCriteria); + builder.setInternet(matchCriteria); + builder.setMms(matchCriteria); + builder.setRcs(matchCriteria); + } + + private void verifyAllCapabilities( + VcnCellUnderlyingNetworkTemplate template, + int expectMatchCriteriaforNonInternet, + int expectMatchCriteriaforInternet) { + assertEquals(expectMatchCriteriaforNonInternet, template.getCbs()); + assertEquals(expectMatchCriteriaforNonInternet, template.getDun()); + assertEquals(expectMatchCriteriaforNonInternet, template.getIms()); + assertEquals(expectMatchCriteriaforNonInternet, template.getMms()); + assertEquals(expectMatchCriteriaforNonInternet, template.getRcs()); + + assertEquals(expectMatchCriteriaforInternet, template.getInternet()); } @Test public void testBuilderAndGetters() { - final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); + final VcnCellUnderlyingNetworkTemplate.Builder builder = getTestNetworkTemplateBuilder(); + setAllCapabilities(builder, MATCH_REQUIRED); + + final VcnCellUnderlyingNetworkTemplate networkPriority = builder.build(); + assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered()); assertEquals( TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, @@ -68,6 +99,8 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getSimSpecificCarrierIds()); assertEquals(MATCH_FORBIDDEN, networkPriority.getRoaming()); assertEquals(MATCH_REQUIRED, networkPriority.getOpportunistic()); + + verifyAllCapabilities(networkPriority, MATCH_REQUIRED, MATCH_REQUIRED); } @Test @@ -86,6 +119,8 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe assertEquals(new HashSet(), networkPriority.getSimSpecificCarrierIds()); assertEquals(MATCH_ANY, networkPriority.getRoaming()); assertEquals(MATCH_ANY, networkPriority.getOpportunistic()); + + verifyAllCapabilities(networkPriority, MATCH_ANY, MATCH_REQUIRED); } @Test @@ -111,6 +146,25 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe } } + @Test + public void testBuildFailWithoutRequiredCapabilities() { + try { + new VcnCellUnderlyingNetworkTemplate.Builder().setInternet(MATCH_ANY).build(); + + fail("Expected IAE for missing required capabilities"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testEqualsWithDifferentCapabilities() { + final VcnCellUnderlyingNetworkTemplate left = + new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build(); + final VcnCellUnderlyingNetworkTemplate right = + new VcnCellUnderlyingNetworkTemplate.Builder().setMms(MATCH_REQUIRED).build(); + assertNotEquals(left, right); + } + @Test public void testPersistableBundle() { final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate(); @@ -119,4 +173,16 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe VcnUnderlyingNetworkTemplate.fromPersistableBundle( networkPriority.toPersistableBundle())); } + + @Test + public void testPersistableBundleWithCapabilities() { + final VcnCellUnderlyingNetworkTemplate.Builder builder = getTestNetworkTemplateBuilder(); + setAllCapabilities(builder, MATCH_REQUIRED); + + final VcnCellUnderlyingNetworkTemplate networkPriority = builder.build(); + assertEquals( + networkPriority, + VcnUnderlyingNetworkTemplate.fromPersistableBundle( + networkPriority.toPersistableBundle())); + } } From befced7406a69c0a574a0962d7277bb7634268f5 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 13 Dec 2022 23:01:54 +0000 Subject: [PATCH 0354/1057] APIs to configure capabilities in VCN cell network template This commit exposes APIs enabling caller to configure required and forbidden capabilities in the VCN cell underlying network template so that a cell network MUST match the capability criteria to be selected as the VCN's underlying network. Bug: 245618320 Test: make update-api && make API-Coverage-Bug: 262448529 Change-Id: I3da7afab85f338f147707f724133a83fa08df4a5 --- .../net/vcn/VcnCellUnderlyingNetworkTemplate.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 35f5e9e47f..c3dba33ab8 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -300,7 +300,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for CBS networks. * * @see Builder#setCbs(int) - * @hide */ @MatchCriteria public int getCbs() { @@ -311,7 +310,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for DUN networks. * * @see Builder#setDun(int) - * @hide */ @MatchCriteria public int getDun() { @@ -321,7 +319,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for IMS networks. * * @see Builder#setIms(int) - * @hide */ @MatchCriteria public int getIms() { @@ -331,7 +328,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for INTERNET networks. * * @see Builder#setInternet(int) - * @hide */ @MatchCriteria public int getInternet() { @@ -341,7 +337,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for MMS networks. * * @see Builder#setMms(int) - * @hide */ @MatchCriteria public int getMms() { @@ -352,7 +347,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * Returns the matching criteria for RCS networks. * * @see Builder#setRcs(int) - * @hide */ @MatchCriteria public int getRcs() { @@ -612,7 +606,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for CBS networks. Defaults to {@link * #MATCH_ANY}. * @see NetworkCapabilities#NET_CAPABILITY_CBS - * @hide */ @NonNull public Builder setCbs(@MatchCriteria int matchCriteria) { @@ -633,7 +626,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for DUN networks. Defaults to {@link * #MATCH_ANY}. * @see NetworkCapabilities#NET_CAPABILITY_DUN - * @hide */ @NonNull public Builder setDun(@MatchCriteria int matchCriteria) { @@ -654,7 +646,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for IMS networks. Defaults to {@link * #MATCH_ANY}. * @see NetworkCapabilities#NET_CAPABILITY_IMS - * @hide */ @NonNull public Builder setIms(@MatchCriteria int matchCriteria) { @@ -675,7 +666,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for INTERNET networks. Defaults to {@link * #MATCH_REQUIRED}. * @see NetworkCapabilities#NET_CAPABILITY_INTERNET - * @hide */ @NonNull public Builder setInternet(@MatchCriteria int matchCriteria) { @@ -696,7 +686,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for MMS networks. Defaults to {@link * #MATCH_ANY}. * @see NetworkCapabilities#NET_CAPABILITY_MMS - * @hide */ @NonNull public Builder setMms(@MatchCriteria int matchCriteria) { @@ -717,7 +706,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork * @param matchCriteria the matching criteria for RCS networks. Defaults to {@link * #MATCH_ANY}. * @see NetworkCapabilities#NET_CAPABILITY_RCS - * @hide */ @NonNull public Builder setRcs(@MatchCriteria int matchCriteria) { From ea89a62f9562f99231adf43a6856ea08ab01281d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 14 Dec 2022 20:01:25 +0000 Subject: [PATCH 0355/1057] CTS for VCN improvements This commit adds CTS coverage for APIs of VCN improvements. APIs get covered are: - Methods allow configuring transports that need to be restricted by the VCN - Methods allow configuring capabilities of VCN's underlying networks - Methods and constants that enable VCN to handle data stall with mobility update Bug: 262263040 Bug: 262448529 Bug: 262297702 Test: atest CtsVcnTestCases (new tests) Change-Id: I53c85661351611b98488fe7b329629eaf67118a8 --- .../VcnCellUnderlyingNetworkTemplateTest.java | 42 +++++- .../android/net/vcn/cts/VcnConfigTest.java | 130 ++++++++++++++++++ .../cts/VcnGatewayConnectionConfigTest.java | 51 ++++++- 3 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnConfigTest.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java index 9100bc079d..b640961962 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java @@ -33,8 +33,7 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe private static final Set ALLOWED_PLMN_IDS = Set.of("123456", "12345"); private static final Set ALLOWED_CARRIER_IDS = Set.of(100, 101); - // Package private for use in VcnGatewayConnectionConfigTest - static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { + private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() { return new VcnCellUnderlyingNetworkTemplate.Builder() .setMetered(MATCH_REQUIRED) .setRoaming(MATCH_REQUIRED) @@ -44,19 +43,51 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe .setMinDownstreamBandwidthKbps( MIN_ENTRY_DOWN_BANDWIDTH_KBPS, MIN_EXIT_DOWN_BANDWIDTH_KBPS) .setMinUpstreamBandwidthKbps( - MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_EXIT_UP_BANDWIDTH_KBPS) - .build(); + MIN_ENTRY_UP_BANDWIDTH_KBPS, MIN_EXIT_UP_BANDWIDTH_KBPS); + } + + // Package private for use in VcnGatewayConnectionConfigTest + static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() { + return getTestNetworkTemplateBuilder().build(); + } + + private static void setAllCapabilities( + VcnCellUnderlyingNetworkTemplate.Builder builder, int matchCriteria) { + builder.setCbs(matchCriteria); + builder.setDun(matchCriteria); + builder.setIms(matchCriteria); + builder.setInternet(matchCriteria); + builder.setMms(matchCriteria); + builder.setRcs(matchCriteria); + } + + private static void verifyAllCapabilities( + VcnCellUnderlyingNetworkTemplate template, + int expectMatchCriteriaforNonInternet, + int expectMatchCriteriaforInternet) { + assertEquals(expectMatchCriteriaforNonInternet, template.getCbs()); + assertEquals(expectMatchCriteriaforNonInternet, template.getDun()); + assertEquals(expectMatchCriteriaforNonInternet, template.getIms()); + assertEquals(expectMatchCriteriaforNonInternet, template.getMms()); + assertEquals(expectMatchCriteriaforNonInternet, template.getRcs()); + + assertEquals(expectMatchCriteriaforInternet, template.getInternet()); } @Test public void testBuilderAndGetters() { - final VcnCellUnderlyingNetworkTemplate networkTemplate = getTestNetworkTemplate(); + final VcnCellUnderlyingNetworkTemplate.Builder builder = getTestNetworkTemplateBuilder(); + setAllCapabilities(builder, MATCH_REQUIRED); + + final VcnCellUnderlyingNetworkTemplate networkTemplate = builder.build(); + assertEquals(MATCH_REQUIRED, networkTemplate.getMetered()); assertEquals(MATCH_REQUIRED, networkTemplate.getRoaming()); assertEquals(MATCH_FORBIDDEN, networkTemplate.getOpportunistic()); assertEquals(ALLOWED_PLMN_IDS, networkTemplate.getOperatorPlmnIds()); assertEquals(ALLOWED_CARRIER_IDS, networkTemplate.getSimSpecificCarrierIds()); verifyBandwidthsWithTestValues(networkTemplate); + verifyAllCapabilities(networkTemplate, MATCH_REQUIRED, MATCH_REQUIRED); } @Test @@ -69,6 +100,7 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe assertEquals(new HashSet(), networkTemplate.getOperatorPlmnIds()); assertEquals(new HashSet(), networkTemplate.getSimSpecificCarrierIds()); verifyBandwidthsWithDefaultValues(networkTemplate); + verifyAllCapabilities(networkTemplate, MATCH_ANY, MATCH_REQUIRED); } @Test diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnConfigTest.java new file mode 100644 index 0000000000..55c20b36f1 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnConfigTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn.cts; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.util.ArraySet; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class VcnConfigTest extends VcnTestBase { + private static final VcnGatewayConnectionConfig GATEWAY_CONNECTION_CONFIG = + VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig(); + + private static final Set RESTRICTED_TRANSPORTS_DEFAULT = + Collections.singleton(TRANSPORT_WIFI); + + private static final Set RESTRICTED_TRANSPORTS = new ArraySet<>(); + + static { + RESTRICTED_TRANSPORTS.add(TRANSPORT_WIFI); + RESTRICTED_TRANSPORTS.add(TRANSPORT_CELLULAR); + } + + private final Context mContext; + + public VcnConfigTest() { + mContext = InstrumentationRegistry.getContext(); + } + + private VcnConfig.Builder makeMinimalTestConfigBuilder() { + return new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig(GATEWAY_CONNECTION_CONFIG); + } + + @Test + public void testBuilderAndGettersWithMinimumSet() { + final VcnConfig config = makeMinimalTestConfigBuilder().build(); + + assertEquals( + Collections.singleton(GATEWAY_CONNECTION_CONFIG), + config.getGatewayConnectionConfigs()); + assertEquals( + RESTRICTED_TRANSPORTS_DEFAULT, config.getRestrictedUnderlyingNetworkTransports()); + } + + @Test + public void testBuilderAndGettersWithRestrictedTransports() { + final VcnConfig config = + makeMinimalTestConfigBuilder() + .setRestrictedUnderlyingNetworkTransports(RESTRICTED_TRANSPORTS) + .build(); + + assertEquals( + Collections.singleton(GATEWAY_CONNECTION_CONFIG), + config.getGatewayConnectionConfigs()); + assertEquals(RESTRICTED_TRANSPORTS, config.getRestrictedUnderlyingNetworkTransports()); + } + + private static VcnGatewayConnectionConfig buildGatewayConfig(String gatewayName) { + return new VcnGatewayConnectionConfig.Builder(gatewayName, buildTunnelConnectionParams()) + .addExposedCapability(NET_CAPABILITY_INTERNET) + .build(); + } + + @Test + public void testBuilderAndGettersWithMultipleGatewayConfigs() { + final VcnGatewayConnectionConfig gatewayConfigOne = buildGatewayConfig("gatewayConfigOne"); + final VcnGatewayConnectionConfig gatewayConfigTwo = buildGatewayConfig("gatewayConfigTwo"); + final VcnConfig config = + new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig(gatewayConfigOne) + .addGatewayConnectionConfig(gatewayConfigTwo) + .build(); + + final Set expectedGatewayConfigs = new ArraySet<>(); + expectedGatewayConfigs.add(gatewayConfigOne); + expectedGatewayConfigs.add(gatewayConfigTwo); + assertEquals(expectedGatewayConfigs, config.getGatewayConnectionConfigs()); + } + + @Test + public void testBuilderRequiresGatewayConnectionConfig() { + try { + new VcnConfig.Builder(mContext).build(); + fail("Expected exception due to no VcnGatewayConnectionConfigs provided"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresUniqueGatewayConnectionNames() { + try { + new VcnConfig.Builder(mContext) + .addGatewayConnectionConfig(GATEWAY_CONNECTION_CONFIG) + .addGatewayConnectionConfig(GATEWAY_CONNECTION_CONFIG); + fail("Expected exception due to duplicate gateway connection name"); + } catch (IllegalArgumentException e) { + } + } +} diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 602ad4a395..54979910cb 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -19,9 +19,12 @@ package android.net.vcn.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; 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.ipsec.ike.IkeSessionParams; @@ -37,6 +40,7 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -59,6 +63,9 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { UNDERLYING_NETWORK_TEMPLATES = Collections.unmodifiableList(nwTemplates); } + private static final Set GATEWAY_OPTIONS = + Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); + public static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() { return new VcnGatewayConnectionConfig.Builder( VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams()) @@ -68,7 +75,8 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { .setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES); } - private static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { + // Package private for use in VcnConfigTest + static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() { return buildVcnGatewayConnectionConfigBase().build(); } @@ -110,4 +118,45 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { } catch (IllegalArgumentException e) { } } + + @Test + public void testBuilderAddGatewayOptions() throws Exception { + final VcnGatewayConnectionConfig.Builder builder = buildVcnGatewayConnectionConfigBase(); + + for (int option : GATEWAY_OPTIONS) { + builder.addGatewayOption(option); + } + + final VcnGatewayConnectionConfig gatewayConnConfig = builder.build(); + for (int option : GATEWAY_OPTIONS) { + assertTrue(gatewayConnConfig.hasGatewayOption(option)); + } + } + + @Test + public void testBuilderAddRemoveGatewayOptions() throws Exception { + final VcnGatewayConnectionConfig.Builder builder = buildVcnGatewayConnectionConfigBase(); + + for (int option : GATEWAY_OPTIONS) { + builder.addGatewayOption(option); + } + + for (int option : GATEWAY_OPTIONS) { + builder.removeGatewayOption(option); + } + + final VcnGatewayConnectionConfig gatewayConnConfig = builder.build(); + for (int option : GATEWAY_OPTIONS) { + assertFalse(gatewayConnConfig.hasGatewayOption(option)); + } + } + + @Test + public void testBuilderRequiresValidOption() { + try { + buildVcnGatewayConnectionConfigBase().addGatewayOption(-1); + fail("Expected exception due to the invalid VCN gateway option"); + } catch (IllegalArgumentException e) { + } + } } From b07bbda99216fcacc7867e946a8c4a8d26ffadec Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 19 Nov 2022 00:18:42 +0000 Subject: [PATCH 0356/1057] Store priority class as final in UnderlyingNetworkRecord This commit refactors UnderlyingNetworkRecord to store its priority class as a final field and calculate it during construction. This commit improves the code maintainabiliy in the network selection logic. Bug: 245618320 Test: FrameworksVcnTests, CtsVcnTestCases Change-Id: I346323cb18de935626b2dc6343be41c21fc7f055 --- .../UnderlyingNetworkController.java | 19 +-- .../UnderlyingNetworkRecord.java | 150 +++++++++--------- .../server/vcn/VcnGatewayConnectionTest.java | 8 +- .../vcn/VcnGatewayConnectionTestBase.java | 18 ++- .../NetworkPriorityClassifierTest.java | 66 ++++---- .../UnderlyingNetworkControllerTest.java | 70 +++++--- 6 files changed, 183 insertions(+), 148 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index d474c5d33a..3acbb5e17e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -356,7 +356,7 @@ public class UnderlyingNetworkController { if (!allNetworkPriorities.isEmpty()) { allNetworkPriorities += ", "; } - allNetworkPriorities += record.network + ": " + record.getPriorityClass(); + allNetworkPriorities += record.network + ": " + record.priorityClass; } logInfo( "Selected network changed to " @@ -393,19 +393,20 @@ public class UnderlyingNetworkController { private TreeSet getSortedUnderlyingNetworks() { TreeSet sorted = - new TreeSet<>( - UnderlyingNetworkRecord.getComparator( + new TreeSet<>(UnderlyingNetworkRecord.getComparator()); + + for (UnderlyingNetworkRecord.Builder builder : + mUnderlyingNetworkRecordBuilders.values()) { + if (builder.isValid()) { + final UnderlyingNetworkRecord record = + builder.build( mVcnContext, mConnectionConfig.getVcnUnderlyingNetworkPriorities(), mSubscriptionGroup, mLastSnapshot, mCurrentRecord, - mCarrierConfig)); - - for (UnderlyingNetworkRecord.Builder builder : - mUnderlyingNetworkRecordBuilders.values()) { - if (builder.isValid()) { - sorted.add(builder.build()); + mCarrierConfig); + sorted.add(record); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index 319680e0b0..aea9f4d2db 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -42,53 +42,58 @@ import java.util.Objects; * @hide */ public class UnderlyingNetworkRecord { - private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE; - @NonNull public final Network network; @NonNull public final NetworkCapabilities networkCapabilities; @NonNull public final LinkProperties linkProperties; public final boolean isBlocked; - - private int mPriorityClass = PRIORITY_CLASS_INVALID; + public final boolean isSelected; + public final int priorityClass; @VisibleForTesting(visibility = Visibility.PRIVATE) public UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, - boolean isBlocked) { - this.network = network; - this.networkCapabilities = networkCapabilities; - this.linkProperties = linkProperties; - this.isBlocked = isBlocked; - } - - private int getOrCalculatePriorityClass( + boolean isBlocked, VcnContext vcnContext, List underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig) { - // Never changes after the underlying network record is created. - if (mPriorityClass == PRIORITY_CLASS_INVALID) { - mPriorityClass = - NetworkPriorityClassifier.calculatePriorityClass( - vcnContext, - this, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); - } + this.network = network; + this.networkCapabilities = networkCapabilities; + this.linkProperties = linkProperties; + this.isBlocked = isBlocked; - return mPriorityClass; + this.isSelected = isSelected(this.network, currentlySelected); + + priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + vcnContext, + this, + underlyingNetworkTemplates, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); } - // Used in UnderlyingNetworkController - int getPriorityClass() { - return mPriorityClass; + @VisibleForTesting(visibility = Visibility.PRIVATE) + public UnderlyingNetworkRecord( + @NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, + boolean isBlocked, + boolean isSelected, + int priorityClass) { + this.network = network; + this.networkCapabilities = networkCapabilities; + this.linkProperties = linkProperties; + this.isBlocked = isBlocked; + this.isSelected = isSelected; + + this.priorityClass = priorityClass; } @Override @@ -108,40 +113,32 @@ public class UnderlyingNetworkRecord { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } - static Comparator getComparator( - VcnContext vcnContext, - List underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + /** Returns if two records are equal including their priority classes. */ + public static boolean isEqualIncludingPriorities( + UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) { + if (left != null && right != null) { + return left.equals(right) + && left.isSelected == right.isSelected + && left.priorityClass == right.priorityClass; + } + + return left == right; + } + + static Comparator getComparator() { return (left, right) -> { - final int leftIndex = - left.getOrCalculatePriorityClass( - vcnContext, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); - final int rightIndex = - right.getOrCalculatePriorityClass( - vcnContext, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); + final int leftIndex = left.priorityClass; + final int rightIndex = right.priorityClass; // In the case of networks in the same priority class, prioritize based on other // criteria (eg. actively selected network, link metrics, etc) if (leftIndex == rightIndex) { // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord // fall into the same priority class. - if (isSelected(left, currentlySelected)) { + if (left.isSelected) { return -1; } - if (isSelected(left, currentlySelected)) { + if (right.isSelected) { return 1; } } @@ -150,11 +147,11 @@ public class UnderlyingNetworkRecord { } private static boolean isSelected( - UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) { + Network networkToCheck, UnderlyingNetworkRecord currentlySelected) { if (currentlySelected == null) { return false; } - if (currentlySelected.network == recordToCheck.network) { + if (currentlySelected.network.equals(networkToCheck)) { return true; } return false; @@ -172,16 +169,8 @@ public class UnderlyingNetworkRecord { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); - final int priorityIndex = - getOrCalculatePriorityClass( - vcnContext, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); - - pw.println("Priority index: " + priorityIndex); + pw.println("priorityClass: " + priorityClass); + pw.println("isSelected: " + isSelected); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); @@ -198,8 +187,6 @@ public class UnderlyingNetworkRecord { boolean mIsBlocked; boolean mWasIsBlockedSet; - @Nullable private UnderlyingNetworkRecord mCached; - Builder(@NonNull Network network) { mNetwork = network; } @@ -211,7 +198,6 @@ public class UnderlyingNetworkRecord { void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { mNetworkCapabilities = networkCapabilities; - mCached = null; } @Nullable @@ -221,32 +207,40 @@ public class UnderlyingNetworkRecord { void setLinkProperties(@NonNull LinkProperties linkProperties) { mLinkProperties = linkProperties; - mCached = null; } void setIsBlocked(boolean isBlocked) { mIsBlocked = isBlocked; mWasIsBlockedSet = true; - mCached = null; } boolean isValid() { return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; } - UnderlyingNetworkRecord build() { + UnderlyingNetworkRecord build( + VcnContext vcnContext, + List underlyingNetworkTemplates, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundleWrapper carrierConfig) { if (!isValid()) { throw new IllegalArgumentException( "Called build before UnderlyingNetworkRecord was valid"); } - if (mCached == null) { - mCached = - new UnderlyingNetworkRecord( - mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); - } - - return mCached; + return new UnderlyingNetworkRecord( + mNetwork, + mNetworkCapabilities, + mLinkProperties, + mIsBlocked, + vcnContext, + underlyingNetworkTemplates, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); } } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a4ee2de9f4..692c8a8f08 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -143,9 +143,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS); - UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( - underlyingNetwork, - capBuilder.build(), new LinkProperties(), false); + UnderlyingNetworkRecord record = + getTestNetworkRecord( + underlyingNetwork, capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( VcnGatewayConnectionConfigTest.buildTestConfig(), @@ -211,7 +211,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers(); UnderlyingNetworkRecord record = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities.Builder().build(), underlyingLp, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 7bafd24379..0a18c3d199 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -109,9 +109,23 @@ public class VcnGatewayConnectionTestBase { protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static UnderlyingNetworkRecord getTestNetworkRecord( + Network network, + NetworkCapabilities networkCapabilities, + LinkProperties linkProperties, + boolean isBlocked) { + return new UnderlyingNetworkRecord( + network, + networkCapabilities, + linkProperties, + isBlocked, + false /* isSelected */, + 0 /* priorityClass */); + } + protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), @@ -124,7 +138,7 @@ public class VcnGatewayConnectionTestBase { protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5"; protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), new NetworkCapabilities(), new LinkProperties(), diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index b0d68952c3..bb7da5604e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -25,7 +25,6 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY; -import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.calculatePriorityClass; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; @@ -48,6 +47,7 @@ import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; +import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -64,6 +64,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -135,25 +136,35 @@ public class NetworkPriorityClassifierTest { false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - mWifiNetworkRecord = - new UnderlyingNetworkRecord( - mNetwork, - WIFI_NETWORK_CAPABILITIES, - LINK_PROPERTIES, - false /* isBlocked */); - - mCellNetworkRecord = - new UnderlyingNetworkRecord( - mNetwork, - CELL_NETWORK_CAPABILITIES, - LINK_PROPERTIES, - false /* isBlocked */); - setupSystemService( mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); + + mWifiNetworkRecord = + getTestNetworkRecord( + WIFI_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); + mCellNetworkRecord = + getTestNetworkRecord( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); + } + + private UnderlyingNetworkRecord getTestNetworkRecord( + NetworkCapabilities nc, List underlyingNetworkTemplates) { + return new UnderlyingNetworkRecord( + mNetwork, + nc, + LINK_PROPERTIES, + false /* isBlocked */, + mVcnContext, + underlyingNetworkTemplates, + SUB_GROUP, + mSubscriptionSnapshot, + null /* currentlySelected */, + null /* carrierConfig */); } @Test @@ -490,24 +501,9 @@ public class NetworkPriorityClassifierTest { mSubscriptionSnapshot)); } - private void verifyCalculatePriorityClass( - UnderlyingNetworkRecord networkRecord, int expectedIndex) { - final int priorityIndex = - calculatePriorityClass( - mVcnContext, - networkRecord, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, - SUB_GROUP, - mSubscriptionSnapshot, - null /* currentlySelected */, - null /* carrierConfig */); - - assertEquals(expectedIndex, priorityIndex); - } - @Test public void testCalculatePriorityClass() throws Exception { - verifyCalculatePriorityClass(mCellNetworkRecord, 2); + assertEquals(2, mCellNetworkRecord.priorityClass); } @Test @@ -518,9 +514,11 @@ public class NetworkPriorityClassifierTest { .setSignalStrength(WIFI_RSSI_LOW) .setSsid(SSID) .build(); - final UnderlyingNetworkRecord wifiNetworkRecord = - new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */); - verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY); + final UnderlyingNetworkRecord wifiNetworkRecord = + getTestNetworkRecord( + nc, VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); + + assertEquals(PRIORITY_ANY, wifiNetworkRecord.priorityClass); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index fad9669911..73d0a28091 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -21,7 +21,9 @@ import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WI import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; @@ -321,29 +323,55 @@ public class UnderlyingNetworkControllerTest { .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); } + private static UnderlyingNetworkRecord getTestNetworkRecord( + Network network, + NetworkCapabilities networkCapabilities, + LinkProperties linkProperties, + boolean isBlocked) { + return new UnderlyingNetworkRecord( + network, + networkCapabilities, + linkProperties, + isBlocked, + false /* isSelected */, + 0 /* priorityClass */); + } + @Test public void testUnderlyingNetworkRecordEquals() { UnderlyingNetworkRecord recordA = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); UnderlyingNetworkRecord recordB = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, INITIAL_NETWORK_CAPABILITIES, INITIAL_LINK_PROPERTIES, false /* isBlocked */); UnderlyingNetworkRecord recordC = new UnderlyingNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */, + true /* isSelected */, + -1 /* priorityClass */); + UnderlyingNetworkRecord recordD = + getTestNetworkRecord( mNetwork, UPDATED_NETWORK_CAPABILITIES, UPDATED_LINK_PROPERTIES, false /* isBlocked */); assertEquals(recordA, recordB); - assertNotEquals(recordA, recordC); + assertEquals(recordA, recordC); + assertNotEquals(recordA, recordD); + + assertTrue(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordB)); + assertFalse(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordC)); } @Test @@ -366,6 +394,10 @@ public class UnderlyingNetworkControllerTest { .build(); } + private void verifyOnSelectedUnderlyingNetworkChanged(UnderlyingNetworkRecord expectedRecord) { + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + } + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) @@ -384,12 +416,12 @@ public class UnderlyingNetworkControllerTest { cb.onBlockedStatusChanged(mNetwork, false /* isFalse */); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); return cb; } @@ -402,12 +434,12 @@ public class UnderlyingNetworkControllerTest { cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); } @Test @@ -417,12 +449,12 @@ public class UnderlyingNetworkControllerTest { cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), UPDATED_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); } @Test @@ -434,18 +466,16 @@ public class UnderlyingNetworkControllerTest { cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkControllerCb, times(1)) - .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); - verify(mNetworkControllerCb, times(1)) - .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); } @Test @@ -458,18 +488,16 @@ public class UnderlyingNetworkControllerTest { cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, responseNetworkCaps, INITIAL_LINK_PROPERTIES, false /* isBlocked */); - verify(mNetworkControllerCb, times(1)) - .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't // change. cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); - verify(mNetworkControllerCb, times(1)) - .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); } @Test @@ -479,12 +507,12 @@ public class UnderlyingNetworkControllerTest { cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); UnderlyingNetworkRecord expectedRecord = - new UnderlyingNetworkRecord( + getTestNetworkRecord( mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), INITIAL_LINK_PROPERTIES, true /* isBlocked */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); + verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); } @Test From a5a1cd505345ff6c68a8f4269787e7534344b497 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 19 Nov 2022 00:18:42 +0000 Subject: [PATCH 0357/1057] Support selecting non-INTERNET networks as underlying networks This commit allows VCN to select underlying Cell networks according to caller configured network capabilities instead of always only selecting INTERNET networks as underlying networks. This commit also makes sure that if all of the network candidates fail to match caller configured network templates, VCN can still select an INTERNET network as a fallback but will never select a non-INTERNET network. Bug: 245618320 Test: FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I6eca0331e4bc6804a500fbed9909bb91b1e80d2d --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 5 + .../NetworkPriorityClassifier.java | 44 ++- .../UnderlyingNetworkController.java | 123 +++++-- .../VcnCellUnderlyingNetworkTemplateTest.java | 3 +- .../vcn/VcnGatewayConnectionConfigTest.java | 12 +- .../NetworkPriorityClassifierTest.java | 76 ++++- .../UnderlyingNetworkControllerTest.java | 314 +++++++++++++++++- 7 files changed, 519 insertions(+), 58 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index c3dba33ab8..38b3174abd 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -353,6 +353,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_RCS); } + /** @hide */ + public Map getCapabilitiesMatchCriteria() { + return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria)); + } + @Override public int hashCode() { return Objects.hash( diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 2f84fddc72..2141eba3be 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -15,6 +15,7 @@ */ package com.android.server.vcn.routeselection; +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_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -45,6 +46,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.VcnContext; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -69,9 +71,23 @@ class NetworkPriorityClassifier { @VisibleForTesting(visibility = Visibility.PRIVATE) static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; - /** Priority for any other networks (including unvalidated, etc) */ + /** + * Priority for networks that VCN can fall back to. + * + *

    If none of the network candidates are validated or match any template, VCN will fall back + * to any INTERNET network. + */ @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PRIORITY_ANY = Integer.MAX_VALUE; + static final int PRIORITY_FALLBACK = Integer.MAX_VALUE; + + /** + * Priority for networks that cannot be selected as VCN's underlying networks. + * + *

    VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any + * template as the underlying network. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_INVALID = -1; /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */ public static int calculatePriorityClass( @@ -86,12 +102,12 @@ class NetworkPriorityClassifier { if (networkRecord.isBlocked) { logWtf("Network blocked for System Server: " + networkRecord.network); - return PRIORITY_ANY; + return PRIORITY_INVALID; } if (snapshot == null) { logWtf("Got null snapshot"); - return PRIORITY_ANY; + return PRIORITY_INVALID; } int priorityIndex = 0; @@ -108,7 +124,13 @@ class NetworkPriorityClassifier { } priorityIndex++; } - return PRIORITY_ANY; + + final NetworkCapabilities caps = networkRecord.networkCapabilities; + if (caps.hasCapability(NET_CAPABILITY_INTERNET) + || (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST))) { + return PRIORITY_FALLBACK; + } + return PRIORITY_INVALID; } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -297,6 +319,18 @@ class NetworkPriorityClassifier { return false; } + for (Map.Entry entry : + networkPriority.getCapabilitiesMatchCriteria().entrySet()) { + final int cap = entry.getKey(); + final int matchCriteria = entry.getValue(); + + if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { + return false; + } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { + return false; + } + } + return true; } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 3acbb5e17e..6afa795e96 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -16,6 +16,9 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.VcnManagementService.LOCAL_LOG; @@ -32,6 +35,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; @@ -40,6 +44,7 @@ import android.os.ParcelUuid; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -49,6 +54,7 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -126,6 +132,63 @@ public class UnderlyingNetworkController { registerOrUpdateNetworkRequests(); } + private static class CapabilityMatchCriteria { + public final int capability; + public final int matchCriteria; + + CapabilityMatchCriteria(int capability, int matchCriteria) { + this.capability = capability; + this.matchCriteria = matchCriteria; + } + + @Override + public int hashCode() { + return Objects.hash(capability, matchCriteria); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof CapabilityMatchCriteria)) { + return false; + } + + final CapabilityMatchCriteria rhs = (CapabilityMatchCriteria) other; + return capability == rhs.capability && matchCriteria == rhs.matchCriteria; + } + } + + private static Set> dedupAndGetCapRequirementsForCell( + VcnGatewayConnectionConfig connectionConfig) { + final Set> dedupedCapsMatchSets = new ArraySet<>(); + + for (VcnUnderlyingNetworkTemplate template : + connectionConfig.getVcnUnderlyingNetworkPriorities()) { + if (template instanceof VcnCellUnderlyingNetworkTemplate) { + final Set capsMatchSet = new ArraySet<>(); + + for (Map.Entry entry : + ((VcnCellUnderlyingNetworkTemplate) template) + .getCapabilitiesMatchCriteria() + .entrySet()) { + + final int capability = entry.getKey(); + final int matchCriteria = entry.getValue(); + if (matchCriteria != MATCH_ANY) { + capsMatchSet.add(new CapabilityMatchCriteria(capability, matchCriteria)); + } + } + + dedupedCapsMatchSets.add(capsMatchSet); + } + } + + dedupedCapsMatchSets.add( + Collections.singleton( + new CapabilityMatchCriteria( + NetworkCapabilities.NET_CAPABILITY_INTERNET, MATCH_REQUIRED))); + return dedupedCapsMatchSets; + } + private void registerOrUpdateNetworkRequests() { NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; NetworkCallback oldWifiCallback = mWifiBringupCallback; @@ -158,11 +221,14 @@ public class UnderlyingNetworkController { getWifiNetworkRequest(), mWifiBringupCallback, mHandler); for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { - final NetworkBringupCallback cb = new NetworkBringupCallback(); - mCellBringupCallbacks.add(cb); + for (Set capsMatchCriteria : + dedupAndGetCapRequirementsForCell(mConnectionConfig)) { + final NetworkBringupCallback cb = new NetworkBringupCallback(); + mCellBringupCallbacks.add(cb); - mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), cb, mHandler); + mConnectivityManager.requestBackgroundNetwork( + getCellNetworkRequestForSubId(subId, capsMatchCriteria), cb, mHandler); + } } } else { mRouteSelectionCallback = null; @@ -214,6 +280,13 @@ public class UnderlyingNetworkController { .build(); } + private NetworkRequest.Builder getBaseWifiNetworkRequestBuilder() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); + } + /** * Builds the WiFi bringup request * @@ -224,10 +297,7 @@ public class UnderlyingNetworkController { * but will NEVER bring up a Carrier WiFi network itself. */ private NetworkRequest getWifiNetworkRequest() { - return getBaseNetworkRequestBuilder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) - .build(); + return getBaseWifiNetworkRequestBuilder().build(); } /** @@ -238,9 +308,7 @@ public class UnderlyingNetworkController { * pace to effectively select a short-lived WiFi offload network. */ private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() { - return getBaseNetworkRequestBuilder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + return getBaseWifiNetworkRequestBuilder() // Ensure wifi updates signal strengths when crossing this threshold. .setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig)) .build(); @@ -254,9 +322,7 @@ public class UnderlyingNetworkController { * pace to effectively select away from a failing WiFi network. */ private NetworkRequest getWifiExitRssiThresholdNetworkRequest() { - return getBaseNetworkRequestBuilder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + return getBaseWifiNetworkRequestBuilder() // Ensure wifi updates signal strengths when crossing this threshold. .setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig)) .build(); @@ -273,11 +339,25 @@ public class UnderlyingNetworkController { *

    Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier. */ - private NetworkRequest getCellNetworkRequestForSubId(int subId) { - return getBaseNetworkRequestBuilder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) - .build(); + private NetworkRequest getCellNetworkRequestForSubId( + int subId, Set capsMatchCriteria) { + final NetworkRequest.Builder nrBuilder = + getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)); + + for (CapabilityMatchCriteria capMatchCriteria : capsMatchCriteria) { + final int cap = capMatchCriteria.capability; + final int matchCriteria = capMatchCriteria.matchCriteria; + + if (matchCriteria == MATCH_REQUIRED) { + nrBuilder.addCapability(cap); + } else if (matchCriteria == MATCH_FORBIDDEN) { + nrBuilder.addForbiddenCapability(cap); + } + } + + return nrBuilder.build(); } /** @@ -285,7 +365,6 @@ public class UnderlyingNetworkController { */ private NetworkRequest.Builder getBaseNetworkRequestBuilder() { return new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); @@ -406,7 +485,9 @@ public class UnderlyingNetworkController { mLastSnapshot, mCurrentRecord, mCarrierConfig); - sorted.add(record); + if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) { + sorted.add(record); + } } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index 1f6bb21506..1569613123 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -32,7 +32,8 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe private static final Set ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set ALLOWED_CARRIER_IDS = new HashSet<>(); - private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() { + // Public for use in UnderlyingNetworkControllerTest + public static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() { return new VcnCellUnderlyingNetworkTemplate.Builder() .setMetered(MATCH_FORBIDDEN) .setMinUpstreamBandwidthKbps( diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 40408880a2..1883c85b52 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -100,14 +100,20 @@ public class VcnGatewayConnectionConfigTest { EXPOSED_CAPS); } - // Public for use in VcnGatewayConnectionTest - public static VcnGatewayConnectionConfig buildTestConfig() { + // Public for use in UnderlyingNetworkControllerTest + public static VcnGatewayConnectionConfig buildTestConfig( + List nwTemplates) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES); + newBuilder().setVcnUnderlyingNetworkPriorities(nwTemplates); return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS); } + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig buildTestConfig() { + return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES); + } + private static VcnGatewayConnectionConfig.Builder newBuilder() { // Append a unique identifier to the name prefix to guarantee that all created // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig). diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index bb7da5604e..629e988495 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn.routeselection; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS; @@ -24,7 +25,8 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS; import static com.android.server.vcn.VcnTestUtils.setupSystemService; -import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK; +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; @@ -64,6 +66,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; @@ -103,6 +106,7 @@ public class NetworkPriorityClassifierTest { private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = new NetworkCapabilities.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setSubscriptionIds(Set.of(SUB_ID)) .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) @@ -501,24 +505,72 @@ public class NetworkPriorityClassifierTest { mSubscriptionSnapshot)); } + private void verifyMatchCellWithRequiredCapabilities( + VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) { + assertEquals( + expectMatch, + checkMatchesCellPriorityRule( + mVcnContext, + template, + mCellNetworkRecord, + SUB_GROUP, + mSubscriptionSnapshot)); + } + + @Test + public void testMatchCell() { + final VcnCellUnderlyingNetworkTemplate template = + getCellNetworkPriorityBuilder().setInternet(MATCH_REQUIRED).build(); + verifyMatchCellWithRequiredCapabilities(template, true /* expectMatch */); + } + + @Test + public void testMatchCellFail_RequiredCapabilitiesMissing() { + final VcnCellUnderlyingNetworkTemplate template = + getCellNetworkPriorityBuilder().setCbs(MATCH_REQUIRED).build(); + verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */); + } + + @Test + public void testMatchCellFail_ForbiddenCapabilitiesFound() { + final VcnCellUnderlyingNetworkTemplate template = + getCellNetworkPriorityBuilder().setDun(MATCH_FORBIDDEN).build(); + verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */); + } + @Test public void testCalculatePriorityClass() throws Exception { assertEquals(2, mCellNetworkRecord.priorityClass); } - @Test - public void testCalculatePriorityClassFailToMatchAny() throws Exception { - final NetworkCapabilities nc = + private void checkCalculatePriorityClassFailToMatchAny( + boolean hasInternet, int expectedPriorityClass) throws Exception { + final List templatesRequireDun = + Collections.singletonList( + new VcnCellUnderlyingNetworkTemplate.Builder() + .setDun(MATCH_REQUIRED) + .build()); + + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setSignalStrength(WIFI_RSSI_LOW) - .setSsid(SSID) - .build(); + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + if (hasInternet) { + ncBuilder.addCapability(NET_CAPABILITY_INTERNET); + } - final UnderlyingNetworkRecord wifiNetworkRecord = - getTestNetworkRecord( - nc, VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); + final UnderlyingNetworkRecord nonDunNetworkRecord = + getTestNetworkRecord(ncBuilder.build(), templatesRequireDun); - assertEquals(PRIORITY_ANY, wifiNetworkRecord.priorityClass); + assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass); + } + + @Test + public void testCalculatePriorityClassFailToMatchAny_InternetNetwork() throws Exception { + checkCalculatePriorityClassFailToMatchAny(true /* hasInternet */, PRIORITY_FALLBACK); + } + + @Test + public void testCalculatePriorityClassFailToMatchAny_NonInternetNetwork() throws Exception { + checkCalculatePriorityClassFailToMatchAny(false /* hasInternet */, PRIORITY_INVALID); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 73d0a28091..2941fdea20 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -16,6 +16,14 @@ package com.android.server.vcn.routeselection; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_FORBIDDEN; +import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_REQUIRED; + import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; @@ -30,6 +38,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -44,7 +53,10 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; +import android.net.vcn.VcnCellUnderlyingNetworkTemplateTest; import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.ParcelUuid; import android.os.test.TestLooper; import android.telephony.CarrierConfigManager; @@ -66,7 +78,10 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -97,11 +112,39 @@ public class UnderlyingNetworkControllerTest { .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build(); + private static final NetworkCapabilities DUN_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .build(); + + private static final NetworkCapabilities CBS_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_CBS) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .build(); + private static final LinkProperties INITIAL_LINK_PROPERTIES = getLinkPropertiesWithName("initial_iface"); private static final LinkProperties UPDATED_LINK_PROPERTIES = getLinkPropertiesWithName("updated_iface"); + private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_DUN = + new VcnCellUnderlyingNetworkTemplate.Builder() + .setInternet(MATCH_ANY) + .setDun(MATCH_REQUIRED) + .build(); + + private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_CBS = + new VcnCellUnderlyingNetworkTemplate.Builder() + .setInternet(MATCH_ANY) + .setCbs(MATCH_REQUIRED) + .build(); + @Mock private Context mContext; @Mock private VcnNetworkProvider mVcnNetworkProvider; @Mock private ConnectivityManager mConnectivityManager; @@ -203,6 +246,107 @@ public class UnderlyingNetworkControllerTest { any()); } + private void verifyRequestBackgroundNetwork( + ConnectivityManager cm, + int expectedSubId, + Set expectedRequiredCaps, + Set expectedForbiddenCaps) { + verify(cm) + .requestBackgroundNetwork( + eq( + getCellRequestForSubId( + expectedSubId, + expectedRequiredCaps, + expectedForbiddenCaps)), + any(NetworkBringupCallback.class), + any()); + } + + @Test + public void testNetworkCallbacksRegisteredOnStartupForNonInternetCapabilities() { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + + // Build network templates + final List networkTemplates = new ArrayList(); + + networkTemplates.add( + VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder() + .setDun(MATCH_REQUIRED) + .setInternet(MATCH_ANY) + .build()); + + networkTemplates.add( + VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder() + .setMms(MATCH_REQUIRED) + .setCbs(MATCH_FORBIDDEN) + .setInternet(MATCH_ANY) + .build()); + + // Start UnderlyingNetworkController + new UnderlyingNetworkController( + mVcnContext, + VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates), + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkControllerCb); + + // Verifications + for (final int subId : INITIAL_SUB_IDS) { + verifyRequestBackgroundNetwork( + cm, + subId, + Collections.singleton(NET_CAPABILITY_INTERNET), + Collections.emptySet()); + verifyRequestBackgroundNetwork( + cm, subId, Collections.singleton(NET_CAPABILITY_DUN), Collections.emptySet()); + verifyRequestBackgroundNetwork( + cm, + subId, + Collections.singleton(NET_CAPABILITY_MMS), + Collections.singleton(NET_CAPABILITY_CBS)); + } + } + + @Test + public void testNetworkCallbacksRegisteredOnStartupWithDedupedtCapabilities() { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + + // Build network templates + final List networkTemplates = new ArrayList(); + final VcnCellUnderlyingNetworkTemplate.Builder builder = + new VcnCellUnderlyingNetworkTemplate.Builder() + .setMms(MATCH_REQUIRED) + .setCbs(MATCH_FORBIDDEN) + .setInternet(MATCH_ANY); + + networkTemplates.add(builder.setMetered(MATCH_REQUIRED).build()); + networkTemplates.add(builder.setMetered(MATCH_FORBIDDEN).build()); + + // Start UnderlyingNetworkController + new UnderlyingNetworkController( + mVcnContext, + VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates), + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkControllerCb); + + // Verifications + for (final int subId : INITIAL_SUB_IDS) { + verifyRequestBackgroundNetwork( + cm, + subId, + Collections.singleton(NET_CAPABILITY_INTERNET), + Collections.emptySet()); + verifyRequestBackgroundNetwork( + cm, + subId, + Collections.singleton(NET_CAPABILITY_MMS), + Collections.singleton(NET_CAPABILITY_CBS)); + } + } + private void verifyNetworkRequestsRegistered(Set expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( @@ -212,8 +356,13 @@ public class UnderlyingNetworkControllerTest { for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getCellRequestForSubId(subId)), - any(NetworkBringupCallback.class), any()); + eq( + getCellRequestForSubId( + subId, + Collections.singleton(NET_CAPABILITY_INTERNET), + Collections.emptySet())), + any(NetworkBringupCallback.class), + any()); } verify(mConnectivityManager) @@ -255,6 +404,7 @@ public class UnderlyingNetworkControllerTest { private NetworkRequest getWifiRequest(Set netCapsSubIds) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setSubscriptionIds(netCapsSubIds) .build(); } @@ -263,6 +413,7 @@ public class UnderlyingNetworkControllerTest { // TODO (b/187991063): Add tests for carrier-config based thresholds return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setSubscriptionIds(netCapsSubIds) .setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) .build(); @@ -272,16 +423,27 @@ public class UnderlyingNetworkControllerTest { // TODO (b/187991063): Add tests for carrier-config based thresholds return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setSubscriptionIds(netCapsSubIds) .setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) .build(); } - private NetworkRequest getCellRequestForSubId(int subId) { - return getExpectedRequestBase() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) - .build(); + private NetworkRequest getCellRequestForSubId( + int subId, Set requiredCaps, Set forbiddenCaps) { + final NetworkRequest.Builder nqBuilder = + getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)); + + for (int cap : requiredCaps) { + nqBuilder.addCapability(cap); + } + for (int cap : forbiddenCaps) { + nqBuilder.addForbiddenCapability(cap); + } + + return nqBuilder.build(); } private NetworkRequest getRouteSelectionRequest(Set netCapsSubIds) { @@ -303,7 +465,6 @@ public class UnderlyingNetworkControllerTest { private NetworkRequest.Builder getExpectedRequestBase() { final NetworkRequest.Builder builder = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); @@ -506,13 +667,7 @@ public class UnderlyingNetworkControllerTest { cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); - UnderlyingNetworkRecord expectedRecord = - getTestNetworkRecord( - mNetwork, - buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), - INITIAL_LINK_PROPERTIES, - true /* isBlocked */); - verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); + verifyOnSelectedUnderlyingNetworkChanged(null); } @Test @@ -548,5 +703,132 @@ public class UnderlyingNetworkControllerTest { verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); } - // TODO (b/187991063): Add tests for network prioritization + private UnderlyingNetworkListener setupControllerAndGetNetworkListener( + List networkTemplates) { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + + new UnderlyingNetworkController( + mVcnContext, + VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates), + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkControllerCb); + + verify(cm) + .registerNetworkCallback( + eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), + mUnderlyingNetworkListenerCaptor.capture(), + any()); + + return mUnderlyingNetworkListenerCaptor.getValue(); + } + + private UnderlyingNetworkRecord bringupNetworkAndGetRecord( + UnderlyingNetworkListener cb, + NetworkCapabilities requestNetworkCaps, + List underlyingNetworkTemplates, + UnderlyingNetworkRecord currentlySelected) { + final Network network = mock(Network.class); + final NetworkCapabilities responseNetworkCaps = + buildResponseNwCaps(requestNetworkCaps, INITIAL_SUB_IDS); + + cb.onAvailable(network); + cb.onCapabilitiesChanged(network, responseNetworkCaps); + cb.onLinkPropertiesChanged(network, INITIAL_LINK_PROPERTIES); + cb.onBlockedStatusChanged(network, false /* isFalse */); + return new UnderlyingNetworkRecord( + network, + responseNetworkCaps, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */, + mVcnContext, + underlyingNetworkTemplates, + SUB_GROUP, + mSubscriptionSnapshot, + currentlySelected, + null /* carrierConfig */); + } + + @Test + public void testSelectMorePreferredNetwork() { + final List networkTemplates = new ArrayList(); + networkTemplates.add(CELL_TEMPLATE_DUN); + networkTemplates.add(CELL_TEMPLATE_CBS); + + UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); + + // Bring up CBS network + final UnderlyingNetworkRecord cbsNetworkRecord = + bringupNetworkAndGetRecord( + cb, + CBS_NETWORK_CAPABILITIES, + networkTemplates, + null /* currentlySelected */); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + + // Bring up DUN network + final UnderlyingNetworkRecord dunNetworkRecord = + bringupNetworkAndGetRecord( + cb, DUN_NETWORK_CAPABILITIES, networkTemplates, cbsNetworkRecord); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + } + + @Test + public void testNeverSelectLessPreferredNetwork() { + final List networkTemplates = new ArrayList(); + networkTemplates.add(CELL_TEMPLATE_DUN); + networkTemplates.add(CELL_TEMPLATE_CBS); + + UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); + + // Bring up DUN network + final UnderlyingNetworkRecord dunNetworkRecord = + bringupNetworkAndGetRecord( + cb, + DUN_NETWORK_CAPABILITIES, + networkTemplates, + null /* currentlySelected */); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + + // Bring up CBS network + final UnderlyingNetworkRecord cbsNetworkRecord = + bringupNetworkAndGetRecord( + cb, CBS_NETWORK_CAPABILITIES, networkTemplates, dunNetworkRecord); + verify(mNetworkControllerCb, never()) + .onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + } + + @Test + public void testFailtoMatchTemplateAndFallBackToInternetNetwork() { + final List networkTemplates = new ArrayList(); + + networkTemplates.add( + new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build()); + UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); + + // Bring up an Internet network without DUN capability + final UnderlyingNetworkRecord networkRecord = + bringupNetworkAndGetRecord( + cb, + INITIAL_NETWORK_CAPABILITIES, + networkTemplates, + null /* currentlySelected */); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(networkRecord)); + } + + @Test + public void testFailtoMatchTemplateAndNeverFallBackToNonInternetNetwork() { + final List networkTemplates = new ArrayList(); + + networkTemplates.add( + new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build()); + UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); + + bringupNetworkAndGetRecord( + cb, CBS_NETWORK_CAPABILITIES, networkTemplates, null /* currentlySelected */); + + verify(mNetworkControllerCb, never()) + .onSelectedUnderlyingNetworkChanged(any(UnderlyingNetworkRecord.class)); + } } From 3592fba2981d16b29f4ccccd1a4d4b8e7e311a27 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 2 Nov 2022 18:45:37 +0000 Subject: [PATCH 0358/1057] Add experimental support for IPsec tunnel aggregation This change adds implementation support for IPsec tunnel aggregation, allowing servers to send downlink traffic over multiple channels. In cases where a lack of hardware offload of ESP or cases where the throughput is CPU-bound, multiple SAs may improve throughput. Bug: 255859065 Test: atest FrameworksVcnTests Change-Id: I8c8ed14a700fccd36e2783c04bdfd09f649ad3d2 --- .../src/android/net/vcn/VcnManager.java | 17 ++- .../net/vcn/util/PersistableBundleUtils.java | 5 + .../server/vcn/VcnGatewayConnection.java | 106 ++++++++++++++++++ ...cnGatewayConnectionConnectedStateTest.java | 106 +++++++++++++++++- .../vcn/VcnGatewayConnectionTestBase.java | 3 + 5 files changed, 233 insertions(+), 4 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 3a7aea5d51..70cf97308f 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -114,13 +114,28 @@ public class VcnManager { public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY = "vcn_restricted_transports"; + /** + * Key for maximum number of parallel SAs for tunnel aggregation + * + *

    If set to a value > 1, multiple tunnels will be set up, and inbound traffic will be + * aggregated over the various tunnels. + * + *

    Defaults to 1, unless overridden by carrier config + * + * @hide + */ + @NonNull + public static final String VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY = + "vcn_tunnel_aggregation_sa_count_max"; + /** List of Carrier Config options to extract from Carrier Config bundles. @hide */ @NonNull public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS = new String[] { VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, - VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY + VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, }; private static final Map< diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index d22ec0ad45..d6761a2b37 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -573,5 +573,10 @@ public class PersistableBundleUtils { return isEqual(mBundle, other.mBundle); } + + @Override + public String toString() { + return mBundle.toString(); + } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 3be16a1fec..739aff7e87 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -33,6 +33,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -59,6 +60,7 @@ import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; import android.net.annotations.PolicyDirection; +import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; import android.net.ipsec.ike.ChildSessionParams; @@ -67,11 +69,14 @@ import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnManager; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.os.Handler; @@ -169,6 +174,9 @@ import java.util.function.Consumer; public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + /** Default number of parallel SAs requested */ + static final int TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT = 1; + // Matches DataConnection.NETWORK_TYPE private constant, and magic string from // ConnectivityManager#getNetworkTypeName() @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -1980,6 +1988,22 @@ public class VcnGatewayConnection extends StateMachine { mChildConfig, oldChildConfig, mIkeConnectionInfo); + + // Create opportunistic child SAs; this allows SA aggregation in the downlink, + // reducing lock/atomic contention in high throughput scenarios. All SAs will + // share the same UDP encap socket (and keepalives) as necessary, and are + // effectively free. + final int parallelTunnelCount = + mDeps.getParallelTunnelCount(mLastSnapshot, mSubscriptionGroup); + logInfo("Parallel tunnel count: " + parallelTunnelCount); + + for (int i = 0; i < parallelTunnelCount - 1; i++) { + mIkeSession.openChildSession( + buildOpportunisticChildParams(), + new VcnChildSessionCallback( + mCurrentToken, true /* isOpportunistic */)); + } + break; case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); @@ -2350,15 +2374,44 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) public class VcnChildSessionCallback implements ChildSessionCallback { private final int mToken; + private final boolean mIsOpportunistic; + + private boolean mIsChildOpened = false; VcnChildSessionCallback(int token) { + this(token, false /* isOpportunistic */); + } + + /** + * Creates a ChildSessionCallback + * + *

    If configured as opportunistic, transforms will not report initial startup, or + * associated startup failures. This serves the dual purposes of ensuring that if the server + * does not support connection multiplexing, new child SA negotiations will be ignored, and + * at the same time, will notify the VCN session if a successfully negotiated opportunistic + * child SA is subsequently torn down, which could impact uplink traffic if the SA in use + * for outbound/uplink traffic is this opportunistic SA. + * + *

    While inbound SAs can be used in parallel, the IPsec stack explicitly selects the last + * applied outbound transform for outbound traffic. This means that unlike inbound traffic, + * outbound does not benefit from these parallel SAs in the same manner. + */ + VcnChildSessionCallback(int token, boolean isOpportunistic) { mToken = token; + mIsOpportunistic = isOpportunistic; } /** Internal proxy method for injecting of mocked ChildSessionConfiguration */ @VisibleForTesting(visibility = Visibility.PRIVATE) void onOpened(@NonNull VcnChildSessionConfiguration childConfig) { logDbg("ChildOpened for token " + mToken); + + if (mIsOpportunistic) { + logDbg("ChildOpened for opportunistic child; suppressing event message"); + mIsChildOpened = true; + return; + } + childOpened(mToken, childConfig); } @@ -2370,12 +2423,24 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onClosed() { logDbg("ChildClosed for token " + mToken); + + if (mIsOpportunistic && !mIsChildOpened) { + logDbg("ChildClosed for unopened opportunistic child; ignoring"); + return; + } + sessionLost(mToken, null); } @Override public void onClosedExceptionally(@NonNull IkeException exception) { logInfo("ChildClosedExceptionally for token " + mToken, exception); + + if (mIsOpportunistic && !mIsChildOpened) { + logInfo("ChildClosedExceptionally for unopened opportunistic child; ignoring"); + return; + } + sessionLost(mToken, exception); } @@ -2580,6 +2645,30 @@ public class VcnGatewayConnection extends StateMachine { return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams(); } + private ChildSessionParams buildOpportunisticChildParams() { + final ChildSessionParams baseParams = + mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams(); + + final TunnelModeChildSessionParams.Builder builder = + new TunnelModeChildSessionParams.Builder(); + for (ChildSaProposal proposal : baseParams.getChildSaProposals()) { + builder.addChildSaProposal(proposal); + } + + for (IkeTrafficSelector inboundSelector : baseParams.getInboundTrafficSelectors()) { + builder.addInboundTrafficSelectors(inboundSelector); + } + + for (IkeTrafficSelector outboundSelector : baseParams.getOutboundTrafficSelectors()) { + builder.addOutboundTrafficSelectors(outboundSelector); + } + + builder.setLifetimeSeconds( + baseParams.getHardLifetimeSeconds(), baseParams.getSoftLifetimeSeconds()); + + return builder.build(); + } + @VisibleForTesting(visibility = Visibility.PRIVATE) VcnIkeSession buildIkeSession(@NonNull Network network) { final int token = ++mCurrentToken; @@ -2680,6 +2769,23 @@ public class VcnGatewayConnection extends StateMachine { return 0; } } + + /** Gets the max number of parallel tunnels allowed for tunnel aggregation. */ + public int getParallelTunnelCount( + TelephonySubscriptionSnapshot snapshot, ParcelUuid subGrp) { + PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp); + int result = TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT; + + if (carrierConfig != null) { + result = + carrierConfig.getInt( + VcnManager.VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, + TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT); + } + + // Guard against tunnel count < 1 + return Math.max(1, result); + } } /** diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 1c21a067bd..aad7a5eb29 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -59,6 +59,7 @@ import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -70,6 +71,7 @@ import android.os.PersistableBundle; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import com.android.server.vcn.util.MtuUtils; @@ -90,6 +92,8 @@ import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { + private static final int PARALLEL_SA_COUNT = 4; + private VcnIkeSession mIkeSession; private VcnNetworkAgent mNetworkAgent; private Network mVcnNetwork; @@ -227,16 +231,29 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection private void verifyVcnTransformsApplied( VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform) throws Exception { + verifyVcnTransformsApplied( + vcnGatewayConnection, + expectForwardTransform, + Collections.singletonList(getChildSessionCallback())); + } + + private void verifyVcnTransformsApplied( + VcnGatewayConnection vcnGatewayConnection, + boolean expectForwardTransform, + List callbacks) + throws Exception { for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { - getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction); + for (VcnChildSessionCallback cb : callbacks) { + cb.onIpSecTransformCreated(makeDummyIpSecTransform(), direction); + } mTestLooper.dispatchAll(); - verify(mIpSecSvc) + verify(mIpSecSvc, times(callbacks.size())) .applyTunnelModeTransform( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } - verify(mIpSecSvc, expectForwardTransform ? times(1) : never()) + verify(mIpSecSvc, expectForwardTransform ? times(callbacks.size()) : never()) .applyTunnelModeTransform( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any()); @@ -416,6 +433,89 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); } + private List openChildAndVerifyParallelSasRequested() + throws Exception { + doReturn(PARALLEL_SA_COUNT) + .when(mDeps) + .getParallelTunnelCount(eq(TEST_SUBSCRIPTION_SNAPSHOT), eq(TEST_SUB_GRP)); + + // Verify scheduled but not canceled when entering ConnectedState + verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */); + triggerChildOpened(); + mTestLooper.dispatchAll(); + + // Verify new child sessions requested + final ArgumentCaptor captor = + ArgumentCaptor.forClass(VcnChildSessionCallback.class); + verify(mIkeSession, times(PARALLEL_SA_COUNT - 1)) + .openChildSession(any(TunnelModeChildSessionParams.class), captor.capture()); + + return captor.getAllValues(); + } + + private List verifyChildOpenedRequestsAndAppliesParallelSas() + throws Exception { + List callbacks = openChildAndVerifyParallelSasRequested(); + + verifyVcnTransformsApplied(mGatewayConnection, false, callbacks); + + // Mock IKE calling of onOpened() + for (VcnChildSessionCallback cb : callbacks) { + cb.onOpened(mock(VcnChildSessionConfiguration.class)); + } + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + return callbacks; + } + + @Test + public void testChildOpenedWithParallelSas() throws Exception { + verifyChildOpenedRequestsAndAppliesParallelSas(); + } + + @Test + public void testOpportunisticSa_ignoresPreOpenFailures() throws Exception { + List callbacks = openChildAndVerifyParallelSasRequested(); + + for (VcnChildSessionCallback cb : callbacks) { + cb.onClosed(); + cb.onClosedExceptionally(mock(IkeException.class)); + } + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); + } + + private void verifyPostOpenFailuresCloseSession(boolean shouldCloseWithException) + throws Exception { + List callbacks = verifyChildOpenedRequestsAndAppliesParallelSas(); + + for (VcnChildSessionCallback cb : callbacks) { + if (shouldCloseWithException) { + cb.onClosed(); + } else { + cb.onClosedExceptionally(mock(IkeException.class)); + } + } + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + } + + @Test + public void testOpportunisticSa_handlesPostOpenFailures_onClosed() throws Exception { + verifyPostOpenFailuresCloseSession(false /* shouldCloseWithException */); + } + + @Test + public void testOpportunisticSa_handlesPostOpenFailures_onClosedExceptionally() + throws Exception { + verifyPostOpenFailuresCloseSession(true /* shouldCloseWithException */); + } + @Test public void testInternalAndDnsAddressesChanged() throws Exception { final List startingInternalAddrs = diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 7bafd24379..1a4149ab7a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -209,6 +209,9 @@ public class VcnGatewayConnectionTestBase { doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); + doReturn(1) + .when(mDeps) + .getParallelTunnelCount(eq(TEST_SUBSCRIPTION_SNAPSHOT), eq(TEST_SUB_GRP)); setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM); setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM); From b4255755fbf631602db6065f7d55f27d6dc4badc Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 18 Jan 2023 17:14:56 -0600 Subject: [PATCH 0359/1057] Update TelephonySubscriptionTracker with new CarrierConfigManager APIs - Replace CarrierConfigChange receiver with listener - Get subset of carrier configs with new API instead of private method Bug: 265961787 Test: atest TelephonySubscriptionTrackerTest Change-Id: I93f14421624ac76bdf84c06cfd4c067bf2ccde7a --- .../vcn/TelephonySubscriptionTracker.java | 38 ++++++------- .../vcn/TelephonySubscriptionTrackerTest.java | 53 ++++++++++--------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index ca4a32f553..099c9ae33b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -16,9 +16,6 @@ package com.android.server.vcn; -import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; @@ -48,7 +45,6 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.util.ArrayList; @@ -109,6 +105,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; + @NonNull + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (int logicalSlotIndex, int subscriptionId, int carrierId, int specificCarrierId) -> + handleActionCarrierConfigChanged(logicalSlotIndex, subscriptionId); + + public TelephonySubscriptionTracker( @NonNull Context context, @NonNull Handler handler, @@ -149,13 +151,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public void register() { final HandlerExecutor executor = new HandlerExecutor(mHandler); final IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); + mCarrierConfigManager.registerCarrierConfigChangeListener(executor, + mCarrierConfigChangeListener); registerCarrierPrivilegesCallbacks(); } @@ -197,6 +200,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); + mCarrierConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); unregisterCarrierPrivilegesCallbacks(); } @@ -273,7 +277,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } /** - * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED + * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED * *

    The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all * serialized on mHandler, avoiding the need for locking. @@ -281,9 +285,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { - case ACTION_CARRIER_CONFIG_CHANGED: - handleActionCarrierConfigChanged(context, intent); - break; case ACTION_MULTI_SIM_CONFIG_CHANGED: handleActionMultiSimConfigChanged(context, intent); break; @@ -310,26 +311,21 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { handleSubscriptionsChanged(); } - private void handleActionCarrierConfigChanged(Context context, Intent intent) { - // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it - // already was for an identified carrier, we can stop waiting for initial load to complete - final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); - final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); - + private void handleActionCarrierConfigChanged(int slotId, int subId) { if (slotId == INVALID_SIM_SLOT_INDEX) { return; } if (SubscriptionManager.isValidSubscriptionId(subId)) { - final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + // Get only configs as needed to save memory. + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) { mReadySubIdsBySlotId.put(slotId, subId); - final PersistableBundle minimized = - PersistableBundleUtils.minimizeBundle( - carrierConfig, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); - if (minimized != null) { - mSubIdToCarrierConfigMap.put(subId, new PersistableBundleWrapper(minimized)); + if (!carrierConfig.isEmpty()) { + mSubIdToCarrierConfigMap.put(subId, + new PersistableBundleWrapper(carrierConfig)); } handleSubscriptionsChanged(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 965b073ff0..34f884b942 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -19,9 +19,6 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; -import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; @@ -143,6 +140,8 @@ public class TelephonySubscriptionTrackerTest { @NonNull private TelephonySubscriptionTrackerCallback mCallback; @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker; + @NonNull private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; + public TelephonySubscriptionTrackerTest() { mContext = mock(Context.class); mTestLooper = new TestLooper(); @@ -173,7 +172,7 @@ public class TelephonySubscriptionTrackerTest { .getSystemService(Context.CARRIER_CONFIG_SERVICE); doReturn(TEST_CARRIER_CONFIG) .when(mCarrierConfigManager) - .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); // subId 1, 2 are in same subGrp, only subId 1 is active doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid(); @@ -189,9 +188,15 @@ public class TelephonySubscriptionTrackerTest { doReturn(2).when(mTelephonyManager).getActiveModemCount(); mCallback = mock(TelephonySubscriptionTrackerCallback.class); + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mTelephonySubscriptionTracker = new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); mTelephonySubscriptionTracker.register(); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any()); doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2)) @@ -239,14 +244,11 @@ public class TelephonySubscriptionTrackerTest { return intent; } - private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { - Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); - intent.putExtra( - EXTRA_SUBSCRIPTION_INDEX, - hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID); - - return intent; + private void sendCarrierConfigChange(boolean hasValidSubscription) { + mCarrierConfigChangeListener.onCarrierConfigChanged( + TEST_SIM_SLOT_INDEX, + hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( @@ -302,14 +304,15 @@ public class TelephonySubscriptionTrackerTest { any(), eq(mHandler)); final IntentFilter filter = getIntentFilter(); - assertEquals(2, filter.countActions()); - assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); + assertEquals(1, filter.countActions()); assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED)); verify(mSubscriptionManager) .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); assertNotNull(getOnSubscriptionsChangedListener()); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), any()); + verify(mTelephonyManager, times(2)) .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any()); verify(mTelephonyManager) @@ -442,7 +445,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); @@ -454,7 +457,7 @@ public class TelephonySubscriptionTrackerTest { .when(mSubscriptionManager) .getAllSubscriptionInfoList(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); // Expect an empty snapshot @@ -465,7 +468,7 @@ public class TelephonySubscriptionTrackerTest { public void testReceiveBroadcast_SlotCleared() throws Exception { setupReadySubIds(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + sendCarrierConfigChange(false /* hasValidSubscription */); mTestLooper.dispatchAll(); verifyNoActiveSubscriptions(); @@ -476,7 +479,7 @@ public class TelephonySubscriptionTrackerTest { public void testReceiveBroadcast_ConfigNotReady() throws Exception { doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any()); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); // No interactions expected; config was not loaded @@ -485,21 +488,21 @@ public class TelephonySubscriptionTrackerTest { @Test public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap()))); } @Test public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); reset(mCallback); @@ -510,12 +513,12 @@ public class TelephonySubscriptionTrackerTest { new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR}); doReturn(updatedConfig) .when(mCarrierConfigManager) - .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); Map subIdToCarrierConfigMap = new HashMap<>(); subIdToCarrierConfigMap.put( TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig)); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback) @@ -530,13 +533,13 @@ public class TelephonySubscriptionTrackerTest { @Test public void testSlotClearedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + sendCarrierConfigChange(false /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback) .onNewSnapshot( From 6f5b19b5f6fe5925db9782bf00da0292c8cd7f96 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 27 Jan 2023 20:03:01 +0000 Subject: [PATCH 0360/1057] Define @IntDef for setRestrictedUnderlyingNetworkTransports This commit also improves the API doc to explain the result of a network being restricted. Bug: 262448368 Test: make Change-Id: Idb7fde0f925048b4abba55b6f6b74a27c0a37bd3 --- .../src/android/net/vcn/VcnConfig.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index dcf002613b..6f9c9dd918 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -22,6 +22,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -37,6 +38,10 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -54,6 +59,17 @@ import java.util.Set; public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"TRANSPORT_"}, + value = { + NetworkCapabilities.TRANSPORT_CELLULAR, + NetworkCapabilities.TRANSPORT_WIFI, + }) + @Target({ElementType.TYPE_USE}) + public @interface VcnUnderlyingNetworkTransport {} + private static final Set ALLOWED_TRANSPORTS = new ArraySet<>(); static { @@ -164,7 +180,7 @@ public final class VcnConfig implements Parcelable { * @see Builder#setRestrictedUnderlyingNetworkTransports(Set) */ @NonNull - public Set getRestrictedUnderlyingNetworkTransports() { + public Set<@VcnUnderlyingNetworkTransport Integer> getRestrictedUnderlyingNetworkTransports() { return Collections.unmodifiableSet(mRestrictedTransports); } @@ -308,16 +324,20 @@ public final class VcnConfig implements Parcelable { /** * Sets transports that will be restricted by the VCN. * - * @param transports transports that will be restricted by VCN. Networks that include any - * of the transports will be marked as restricted. Only {@link - * NetworkCapabilities#TRANSPORT_WIFI} and {@link - * NetworkCapabilities#TRANSPORT_CELLULAR} are allowed. {@link + *

    In general, apps will not be able to bind to, or use a restricted network. In other + * words, unless the network type is marked restricted, any app can opt to use underlying + * networks, instead of through the VCN. + * + * @param transports transports that will be restricted by VCN. Networks that include any of + * the transports will be marked as restricted. {@link * NetworkCapabilities#TRANSPORT_WIFI} is marked restricted by default. * @return this {@link Builder} instance, for chaining * @throws IllegalArgumentException if the input contains unsupported transport types. + * @see NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED */ @NonNull - public Builder setRestrictedUnderlyingNetworkTransports(@NonNull Set transports) { + public Builder setRestrictedUnderlyingNetworkTransports( + @NonNull Set<@VcnUnderlyingNetworkTransport Integer> transports) { validateRestrictedTransportsOrThrow(transports); mRestrictedTransports.clear(); From 9b32c532d0fbab2e61f6cb09a3d6d56269f97eab Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Mon, 6 Feb 2023 02:13:31 +0000 Subject: [PATCH 0361/1057] Add new IKE option in IkeSessionParamsUtils This commit updates IkeSessionParamsUtils to be able to encode/decode IkeSessionParams with IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF. Bug: 259000745 Test: atest IkeSessionParamsUtilsTest Change-Id: I6dd24893cf3343df05ae41e657ff082145c1e8ff --- .../IkeSessionParamsUtils.java | 1 + .../IkeSessionParamsUtilsTest.java | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index d6f191e311..1b661e7935 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -93,6 +93,7 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF); } /** diff --git a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index e4add80981..9f7d239093 100644 --- a/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -16,9 +16,9 @@ package android.net.vcn.persistablebundleutils; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF; import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION; import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES; -import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.isIkeOptionValid; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.telephony.TelephonyManager.APPTYPE_USIM; @@ -160,13 +160,11 @@ public class IkeSessionParamsUtilsTest { .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) - .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY); - if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)) { - builder.addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION); - } - if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) { - builder.addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES); - } + .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY) + .addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION) + .addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES) + .addIkeOption(IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF); + verifyPersistableBundleEncodeDecodeIsLossless(builder.build()); } From fb534f1e03fb08d3a823fdfffa29c4ba05455319 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 15 Feb 2023 08:53:02 +0000 Subject: [PATCH 0362/1057] Add CTS for new VCN 4500 NAT timeout This change ensures the API accepts only the right value ranges. Bug: 259000745 Test: atest CtsVcnTestCases Change-Id: Ief10727dbe05b66b49cea9c4c4e16bf137d398f2 --- .../cts/VcnGatewayConnectionConfigTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 54979910cb..b48be30571 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -159,4 +159,27 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { } catch (IllegalArgumentException e) { } } + + @Test + public void testBuilderSetMinUdpPort4500NatTimeout() { + final int natTimeoutSeconds = 600; + final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfigBase() + .setMinUdpPort4500NatTimeoutSeconds(600).build(); + assertEquals(natTimeoutSeconds, gatewayConnConfig.getMinUdpPort4500NatTimeoutSeconds()); + } + + @Test + public void testBuilderSetMinUdpPort4500NatTimeout_invalidValues() { + try { + buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(-1); + fail("Expected exception due to invalid timeout range"); + } catch (IllegalArgumentException e) { + } + + try { + buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(119); + fail("Expected exception due to invalid timeout range"); + } catch (IllegalArgumentException e) { + } + } } From 5d30e0ec0153ce2d51ee46ed67af8a0b369700ae Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 15 Feb 2023 06:38:46 +0000 Subject: [PATCH 0363/1057] Add API for VCN configuration of UDP port 4500 NAT Timeouts This patch adds an API to allow VCN providers to configure the UDP port 4500 hint to improve the power implications of a VPN over the VCN. Bug: 259000745 Test: atest FrameworksVcnTests Change-Id: Id464ab43fa15d5f6a693f73932d95d9822320acb --- .../net/vcn/VcnGatewayConnectionConfig.java | 59 +++++++++++++++++++ .../src/android/net/vcn/VcnTransportInfo.java | 53 +++++++++++++---- .../server/vcn/VcnGatewayConnection.java | 10 +++- .../vcn/VcnGatewayConnectionConfigTest.java | 5 +- .../android/net/vcn/VcnTransportInfoTest.java | 34 ++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 8 +++ .../vcn/VcnGatewayConnectionTestBase.java | 8 ++- 7 files changed, 161 insertions(+), 16 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 4c9d150ec4..a40fb154c2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -81,6 +81,12 @@ import java.util.concurrent.TimeUnit; * */ public final class VcnGatewayConnectionConfig { + /** @hide */ + public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; + + /** @hide */ + public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS = 120; + // TODO: Use MIN_MTU_V6 once it is public, @hide @VisibleForTesting(visibility = Visibility.PRIVATE) static final int MIN_MTU_V6 = 1280; @@ -225,6 +231,10 @@ public final class VcnGatewayConnectionConfig { private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; @NonNull private final long[] mRetryIntervalsMs; + private static final String MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY = + "mMinUdpPort4500NatTimeoutSeconds"; + private final int mMinUdpPort4500NatTimeoutSeconds; + private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; @NonNull private final Set mGatewayOptions; @@ -236,12 +246,14 @@ public final class VcnGatewayConnectionConfig { @NonNull List underlyingNetworkTemplates, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, + @NonNull int minUdpPort4500NatTimeoutSeconds, @NonNull Set gatewayOptions) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; + mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); @@ -301,6 +313,10 @@ public final class VcnGatewayConnectionConfig { mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); + mMinUdpPort4500NatTimeoutSeconds = + in.getInt( + MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, + MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); validate(); } @@ -323,6 +339,12 @@ public final class VcnGatewayConnectionConfig { Preconditions.checkArgument( mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + Preconditions.checkArgument( + mMinUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || mMinUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "minUdpPort4500NatTimeoutSeconds must be at least 120s"); + for (int option : mGatewayOptions) { validateGatewayOption(option); } @@ -451,6 +473,15 @@ public final class VcnGatewayConnectionConfig { return mMaxMtu; } + /** + * Retrieves the maximum supported IKEv2/IPsec NATT keepalive timeout. + * + * @see Builder#setMinUdpPort4500NatTimeoutSeconds(int) + */ + public int getMinUdpPort4500NatTimeoutSeconds() { + return mMinUdpPort4500NatTimeoutSeconds; + } + /** * Checks if the given VCN gateway option is enabled. * @@ -496,6 +527,7 @@ public final class VcnGatewayConnectionConfig { result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); + result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds); return result; } @@ -509,6 +541,7 @@ public final class VcnGatewayConnectionConfig { mUnderlyingNetworkTemplates, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu, + mMinUdpPort4500NatTimeoutSeconds, mGatewayOptions); } @@ -525,6 +558,7 @@ public final class VcnGatewayConnectionConfig { && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu + && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds && mGatewayOptions.equals(rhs.mGatewayOptions); } @@ -542,6 +576,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; + private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; @NonNull private final Set mGatewayOptions = new ArraySet<>(); @@ -702,6 +737,29 @@ public final class VcnGatewayConnectionConfig { return this; } + /** + * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * + *

    This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN + * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN + * Gateway. + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder setMinUdpPort4500NatTimeoutSeconds( + @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) + int minUdpPort4500NatTimeoutSeconds) { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s"); + + mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; + return this; + } + /** * Enables the specified VCN gateway option. * @@ -744,6 +802,7 @@ public final class VcnGatewayConnectionConfig { mUnderlyingNetworkTemplates, mRetryIntervalsMs, mMaxMtu, + mMinUdpPort4500NatTimeoutSeconds, mGatewayOptions); } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 5c47b28a7c..f5469104be 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -17,6 +17,7 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; @@ -49,18 +50,29 @@ import java.util.Objects; public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; + private final int mMinUdpPort4500NatTimeoutSeconds; public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, INVALID_SUBSCRIPTION_ID); + this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); + } + + public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) { + this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds); } public VcnTransportInfo(int subId) { - this(null /* wifiInfo */, subId); + this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } - private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { + public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) { + this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds); + } + + private VcnTransportInfo( + @Nullable WifiInfo wifiInfo, int subId, int minUdpPort4500NatTimeoutSeconds) { mWifiInfo = wifiInfo; mSubId = subId; + mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; } /** @@ -88,16 +100,28 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return mSubId; } + /** + * Get the VCN provided UDP port 4500 NAT timeout + * + * @return the UDP 4500 NAT timeout, or + * VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set. + */ + public int getMinUdpPort4500NatTimeoutSeconds() { + return mMinUdpPort4500NatTimeoutSeconds; + } + @Override public int hashCode() { - return Objects.hash(mWifiInfo, mSubId); + return Objects.hash(mWifiInfo, mSubId, mMinUdpPort4500NatTimeoutSeconds); } @Override public boolean equals(Object o) { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; - return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; + return Objects.equals(mWifiInfo, that.mWifiInfo) + && mSubId == that.mSubId + && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds; } /** {@inheritDoc} */ @@ -110,11 +134,14 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { @NonNull public TransportInfo makeCopy(long redactions) { if ((redactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) != 0) { - return new VcnTransportInfo(null, INVALID_SUBSCRIPTION_ID); + return new VcnTransportInfo( + null, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } return new VcnTransportInfo( - (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId); + (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), + mSubId, + mMinUdpPort4500NatTimeoutSeconds); } @Override @@ -134,6 +161,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSubId); dest.writeParcelable(mWifiInfo, flags); + dest.writeInt(mMinUdpPort4500NatTimeoutSeconds); } @Override @@ -146,16 +174,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { final int subId = in.readInt(); - final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class); + final WifiInfo wifiInfo = + in.readParcelable(null, android.net.wifi.WifiInfo.class); + final int minUdpPort4500NatTimeoutSeconds = in.readInt(); // If all fields are their null values, return null TransportInfo to avoid // leaking information about this being a VCN Network (instead of macro // cellular, etc) - if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { + if (wifiInfo == null + && subId == INVALID_SUBSCRIPTION_ID + && minUdpPort4500NatTimeoutSeconds + == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET) { return null; } - return new VcnTransportInfo(wifiInfo, subId); + return new VcnTransportInfo(wifiInfo, subId, minUdpPort4500NatTimeoutSeconds); } public VcnTransportInfo[] newArray(int size) { diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 739aff7e87..a1ef537ff2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2255,12 +2255,18 @@ public class VcnGatewayConnection extends StateMachine { if (underlyingCaps.hasTransport(TRANSPORT_WIFI) && underlyingCaps.getTransportInfo() instanceof WifiInfo) { final WifiInfo wifiInfo = (WifiInfo) underlyingCaps.getTransportInfo(); - builder.setTransportInfo(new VcnTransportInfo(wifiInfo)); + builder.setTransportInfo( + new VcnTransportInfo( + wifiInfo, + gatewayConnectionConfig.getMinUdpPort4500NatTimeoutSeconds())); } else if (underlyingCaps.hasTransport(TRANSPORT_CELLULAR) && underlyingCaps.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { final TelephonyNetworkSpecifier telNetSpecifier = (TelephonyNetworkSpecifier) underlyingCaps.getNetworkSpecifier(); - builder.setTransportInfo(new VcnTransportInfo(telNetSpecifier.getSubscriptionId())); + builder.setTransportInfo( + new VcnTransportInfo( + telNetSpecifier.getSubscriptionId(), + gatewayConnectionConfig.getMinUdpPort4500NatTimeoutSeconds())); } else { Slog.wtf( TAG, diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 1883c85b52..a1a39ff173 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -82,6 +82,7 @@ public class VcnGatewayConnectionConfigTest { TimeUnit.MINUTES.toMillis(30) }; public static final int MAX_MTU = 1360; + public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120; private static final Set GATEWAY_OPTIONS = Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY); @@ -104,7 +105,9 @@ public class VcnGatewayConnectionConfigTest { public static VcnGatewayConnectionConfig buildTestConfig( List nwTemplates) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setVcnUnderlyingNetworkPriorities(nwTemplates); + newBuilder() + .setVcnUnderlyingNetworkPriorities(nwTemplates) + .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT); return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS); } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 19df3c7526..81814b67f5 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -19,6 +19,7 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.REDACT_NONE; +import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; @@ -37,11 +38,14 @@ import java.util.Arrays; public class VcnTransportInfoTest { private static final int SUB_ID = 1; private static final int NETWORK_ID = 5; + private static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120; private static final WifiInfo WIFI_INFO = new WifiInfo.Builder().setNetworkId(NETWORK_ID).build(); - private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); - private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); + private static final VcnTransportInfo CELL_UNDERLYING_INFO = + new VcnTransportInfo(SUB_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT); + private static final VcnTransportInfo WIFI_UNDERLYING_INFO = + new VcnTransportInfo(WIFI_INFO, MIN_UDP_PORT_4500_NAT_TIMEOUT); @Test public void testGetWifiInfo() { @@ -57,6 +61,16 @@ public class VcnTransportInfoTest { assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId()); } + @Test + public void testGetMinUdpPort4500NatTimeoutSeconds() { + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, + CELL_UNDERLYING_INFO.getMinUdpPort4500NatTimeoutSeconds()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, + WIFI_UNDERLYING_INFO.getMinUdpPort4500NatTimeoutSeconds()); + } + @Test public void testMakeCopyRedactForNetworkSettings() { for (VcnTransportInfo info : Arrays.asList(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO)) { @@ -67,6 +81,10 @@ public class VcnTransportInfoTest { assertNull( ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) .getWifiInfo()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET, + ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getMinUdpPort4500NatTimeoutSeconds()); } } @@ -76,10 +94,18 @@ public class VcnTransportInfoTest { SUB_ID, ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) .getSubId()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getMinUdpPort4500NatTimeoutSeconds()); assertEquals( WifiConfiguration.INVALID_NETWORK_ID, ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) .getWifiInfo().getNetworkId()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getMinUdpPort4500NatTimeoutSeconds()); } @Test @@ -110,8 +136,12 @@ public class VcnTransportInfoTest { public void testParcelNotRedactedForSysUi() { VcnTransportInfo cellRedacted = parcelForSysUi(CELL_UNDERLYING_INFO); assertEquals(SUB_ID, cellRedacted.getSubId()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, cellRedacted.getMinUdpPort4500NatTimeoutSeconds()); VcnTransportInfo wifiRedacted = parcelForSysUi(WIFI_UNDERLYING_INFO); assertEquals(NETWORK_ID, wifiRedacted.getWifiInfo().getNetworkId()); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, wifiRedacted.getMinUdpPort4500NatTimeoutSeconds()); } private VcnTransportInfo parcelForSysUi(VcnTransportInfo vcnTransportInfo) { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index aad7a5eb29..89271e1218 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; +import static android.net.vcn.VcnGatewayConnectionConfigTest.MIN_UDP_PORT_4500_NAT_TIMEOUT; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; @@ -66,6 +67,7 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; +import android.net.vcn.VcnTransportInfo; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; @@ -425,6 +427,12 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertTrue(nc.hasCapability(cap)); } + assertTrue(nc.getTransportInfo() instanceof VcnTransportInfo); + final VcnTransportInfo vcnTransportInfo = (VcnTransportInfo) nc.getTransportInfo(); + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, + vcnTransportInfo.getMinUdpPort4500NatTimeoutSeconds()); + // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is // canceled triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index bb123ffe30..5efbf598f9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; @@ -46,6 +48,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; @@ -127,7 +130,10 @@ public class VcnGatewayConnectionTestBase { protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = getTestNetworkRecord( mock(Network.class, CALLS_REAL_METHODS), - new NetworkCapabilities(), + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUB_ID)) + .build(), new LinkProperties(), false /* blocked */); From f57243cde864532dbf57c5451f1e3326a2c69452 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 14 Feb 2023 19:39:56 +0900 Subject: [PATCH 0364/1057] Add the IP version and encap type to IkeSessionParamsUtils. Test: none yet Change-Id: Iedf220483ce08d618f1ba60c5b652ef8fbf3130d --- .../vcn/persistablebundleutils/IkeSessionParamsUtils.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 1b661e7935..d681a2c38f 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -74,6 +74,9 @@ public final class IkeSessionParamsUtils { private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY"; private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY"; private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY"; + private static final String IP_VERSION_KEY = "IP_VERSION_KEY"; + private static final String ENCAP_TYPE_KEY = "ENCAP_TYPE_KEY"; + // TODO: add DSCP_KEY and IS_IKE_FRAGMENT_SUPPORTED_KEY. // TODO: b/243181760 Use the IKE API when they are exposed @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -156,6 +159,8 @@ public final class IkeSessionParamsUtils { result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); + result.putInt(IP_VERSION_KEY, params.getIpVersion()); + result.putInt(ENCAP_TYPE_KEY, params.getEncapType()); // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new // IKE_OPTION is defined in IKE module and added in the IkeSessionParams @@ -207,6 +212,8 @@ public final class IkeSessionParamsUtils { in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); + builder.setIpVersion(in.getInt(IP_VERSION_KEY)); + builder.setEncapType(in.getInt(ENCAP_TYPE_KEY)); final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); Objects.requireNonNull(configReqListBundle, "Config request list was null"); From ca1e126714509ad27d75b391d70426b3bd5c1515 Mon Sep 17 00:00:00 2001 From: Frank Feng Date: Fri, 17 Feb 2023 16:55:17 -0800 Subject: [PATCH 0365/1057] Update AndroidManifest.xml in cts/ Remove: Bug: 267766325 Test: TH Change-Id: Ibdc2bab558d6eae9ca0a5953f04d21d027160d16 --- Vcn/tests/cts/AndroidManifest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..87525a14a6 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -35,8 +35,6 @@ - From 2b4d9ed1666d0301719ce56740767d4367ddd3ec Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 5 Dec 2022 22:59:05 +0000 Subject: [PATCH 0366/1057] VCN CTS for handling data stall with mobility updates This commit adds a CTS test to verify that VCN will try recovering from a suspected data stall with mobility updates. Bug: 263415068 Test: atest VcnManagerTest (new tests) Change-Id: I18f5645c44aefd9473f3fceb194ad3f5ff71fd68 --- .../android/net/vcn/cts/VcnManagerTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 028c6b790b..6051a5c7a0 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -18,10 +18,12 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; +import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -56,6 +58,7 @@ import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.CapabilitiesChangedEvent; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -137,6 +140,8 @@ public class VcnManagerTest extends VcnTestBase { VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase() .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS) .setVcnUnderlyingNetworkPriorities(nwTemplate) + .addGatewayOption( + VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY) .build()); } @@ -487,6 +492,33 @@ public class VcnManagerTest extends VcnTestBase { } } + @Test + public void testSetVcnConfigOnTestNetworkAndHandleDataStall() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); + + mConnectivityManager.simulateDataStall( + DETECTION_METHOD_DNS_EVENTS, + System.currentTimeMillis(), + vcnSetupResult.vcnNetwork, + new PersistableBundle() /* extra data stall info; unused */); + + injectAndVerifyIkeMobikePackets(testNetworkWrapper.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + }); + } + } + private VcnConfig createVcnConfigPrefersMetered() throws Exception { final List nwTemplates = new ArrayList<>(); nwTemplates.add( From 44310a9ccb0a5ece3e2d63c973d4ee4715787979 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Mar 2023 22:03:12 +0000 Subject: [PATCH 0367/1057] VCN: Require capability matching on test networks for CTS This commit updates NetworkPriorityClassifier to also require capabilty matching on test networks. This allows CTS to select underlying test networks based on their capabilities. Previously capability matching was only done cell networks. To do that this commit adds an abstract method to VcnUnderlyingNetworkTemplate to retrieve capability requirements so that the capability match can be done before the matching logic diverge to different transports. Bug: 263415068 Test: atest VcnManagerTest (new tests) Change-Id: Id6ee75e70dc31851d7d6980ee1bf5eceb843b294 --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 1 + .../net/vcn/VcnUnderlyingNetworkTemplate.java | 4 ++++ .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 11 +++++++++ .../NetworkPriorityClassifier.java | 24 +++++++++---------- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 38b3174abd..46cf0163c0 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -354,6 +354,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** @hide */ + @Override public Map getCapabilitiesMatchCriteria() { return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria)); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 9235d09132..edf2c093bc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -29,6 +29,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Map; import java.util.Objects; /** @@ -307,4 +308,7 @@ public abstract class VcnUnderlyingNetworkTemplate { public int getMinExitDownstreamBandwidthKbps() { return mMinExitDownstreamBandwidthKbps; } + + /** @hide */ + public abstract Map getCapabilitiesMatchCriteria(); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 2544a6d635..2e6b09f032 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -15,6 +15,9 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; @@ -23,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.util.ArraySet; @@ -32,6 +36,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -162,6 +167,12 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return Collections.unmodifiableSet(mSsids); } + /** @hide */ + @Override + public Map getCapabilitiesMatchCriteria() { + return Collections.singletonMap(NET_CAPABILITY_INTERNET, MATCH_REQUIRED); + } + /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ public static final class Builder { private int mMeteredMatchCriteria = MATCH_ANY; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 2141eba3be..7f129ea380 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -171,6 +171,18 @@ class NetworkPriorityClassifier { return false; } + for (Map.Entry entry : + networkPriority.getCapabilitiesMatchCriteria().entrySet()) { + final int cap = entry.getKey(); + final int matchCriteria = entry.getValue(); + + if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { + return false; + } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { + return false; + } + } + if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { return true; } @@ -319,18 +331,6 @@ class NetworkPriorityClassifier { return false; } - for (Map.Entry entry : - networkPriority.getCapabilitiesMatchCriteria().entrySet()) { - final int cap = entry.getKey(); - final int matchCriteria = entry.getValue(); - - if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { - return false; - } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { - return false; - } - } - return true; } From b3f214ff2eee722dd79f1ac4818c30665c4db2de Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 22 Mar 2023 22:13:08 +0000 Subject: [PATCH 0368/1057] Revert "VCN: Require capability matching on test networks for CTS" This reverts commit 44310a9ccb0a5ece3e2d63c973d4ee4715787979. Reason for revert: b/274811188 (unit tests are broken) Bug: 274811188 Test: atest CtsVcnTestCases; atest FrameworksVcnTests Change-Id: Id48ce89650864bbb5c489871dadb9b2714ab6910 --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 1 - .../net/vcn/VcnUnderlyingNetworkTemplate.java | 4 ---- .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 11 --------- .../NetworkPriorityClassifier.java | 24 +++++++++---------- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 46cf0163c0..38b3174abd 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -354,7 +354,6 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** @hide */ - @Override public Map getCapabilitiesMatchCriteria() { return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria)); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index edf2c093bc..9235d09132 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -29,7 +29,6 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Map; import java.util.Objects; /** @@ -308,7 +307,4 @@ public abstract class VcnUnderlyingNetworkTemplate { public int getMinExitDownstreamBandwidthKbps() { return mMinExitDownstreamBandwidthKbps; } - - /** @hide */ - public abstract Map getCapabilitiesMatchCriteria(); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 2e6b09f032..2544a6d635 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -15,9 +15,6 @@ */ package android.net.vcn; -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; - import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; @@ -26,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; -import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.util.ArraySet; @@ -36,7 +32,6 @@ import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -167,12 +162,6 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return Collections.unmodifiableSet(mSsids); } - /** @hide */ - @Override - public Map getCapabilitiesMatchCriteria() { - return Collections.singletonMap(NET_CAPABILITY_INTERNET, MATCH_REQUIRED); - } - /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ public static final class Builder { private int mMeteredMatchCriteria = MATCH_ANY; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 7f129ea380..2141eba3be 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -171,18 +171,6 @@ class NetworkPriorityClassifier { return false; } - for (Map.Entry entry : - networkPriority.getCapabilitiesMatchCriteria().entrySet()) { - final int cap = entry.getKey(); - final int matchCriteria = entry.getValue(); - - if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { - return false; - } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { - return false; - } - } - if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { return true; } @@ -331,6 +319,18 @@ class NetworkPriorityClassifier { return false; } + for (Map.Entry entry : + networkPriority.getCapabilitiesMatchCriteria().entrySet()) { + final int cap = entry.getKey(); + final int matchCriteria = entry.getValue(); + + if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { + return false; + } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { + return false; + } + } + return true; } From 08e7c81a1af9e15fe0d92802ea84b8d2866b6a77 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 22 Mar 2023 16:02:17 -0700 Subject: [PATCH 0369/1057] Add VCN CTS and unit tests to presubmit for VCN changes Verified that VCN CTS and unit tests are runnning in presubmit: https://android-build.corp.google.com/test_investigate/?invocationId=I96600010143119977&testResultId=TR64528561645495936 Bug: 274822877 Test: no function code change Change-Id: Ic3beb9f5966663de386d1aa49d9b06ab227eb5f4 --- Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING diff --git a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING b/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING new file mode 100644 index 0000000000..5b04d884fc --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } + ] +} \ No newline at end of file From 386cf4afcc49dd028ed138a93aa996669f330da4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Mar 2023 22:03:12 +0000 Subject: [PATCH 0370/1057] [Reland] VCN: Require capability matching on test networks for CTS This commit updates NetworkPriorityClassifier to also require capabilty matching on test networks. This allows CTS to select underlying test networks based on their capabilities. Previously capability matching was only done cell networks. To do that this commit adds an abstract method to VcnUnderlyingNetworkTemplate to retrieve capability requirements so that the capability match can be done before the matching logic diverge to different transports. Bug: 263415068 Test: atest VcnManagerTest (new tests) Change-Id: I12377cbd1d721c4100a958fd9a0ea56d87351eec --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 1 + .../net/vcn/VcnUnderlyingNetworkTemplate.java | 4 ++++ .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 11 +++++++++ .../NetworkPriorityClassifier.java | 24 +++++++++---------- .../NetworkPriorityClassifierTest.java | 7 ++++-- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 38b3174abd..46cf0163c0 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -354,6 +354,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** @hide */ + @Override public Map getCapabilitiesMatchCriteria() { return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria)); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 9235d09132..edf2c093bc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -29,6 +29,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Map; import java.util.Objects; /** @@ -307,4 +308,7 @@ public abstract class VcnUnderlyingNetworkTemplate { public int getMinExitDownstreamBandwidthKbps() { return mMinExitDownstreamBandwidthKbps; } + + /** @hide */ + public abstract Map getCapabilitiesMatchCriteria(); } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 2544a6d635..2e6b09f032 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -15,6 +15,9 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; @@ -23,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.util.ArraySet; @@ -32,6 +36,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -162,6 +167,12 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return Collections.unmodifiableSet(mSsids); } + /** @hide */ + @Override + public Map getCapabilitiesMatchCriteria() { + return Collections.singletonMap(NET_CAPABILITY_INTERNET, MATCH_REQUIRED); + } + /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ public static final class Builder { private int mMeteredMatchCriteria = MATCH_ANY; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 2141eba3be..7f129ea380 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -171,6 +171,18 @@ class NetworkPriorityClassifier { return false; } + for (Map.Entry entry : + networkPriority.getCapabilitiesMatchCriteria().entrySet()) { + final int cap = entry.getKey(); + final int matchCriteria = entry.getValue(); + + if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { + return false; + } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { + return false; + } + } + if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { return true; } @@ -319,18 +331,6 @@ class NetworkPriorityClassifier { return false; } - for (Map.Entry entry : - networkPriority.getCapabilitiesMatchCriteria().entrySet()) { - final int cap = entry.getKey(); - final int matchCriteria = entry.getValue(); - - if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { - return false; - } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { - return false; - } - } - return true; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 629e988495..2266041085 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -95,6 +95,7 @@ public class NetworkPriorityClassifierTest { private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setSignalStrength(WIFI_RSSI) .setSsid(SSID) .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) @@ -509,12 +510,14 @@ public class NetworkPriorityClassifierTest { VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) { assertEquals( expectMatch, - checkMatchesCellPriorityRule( + checkMatchesPriorityRule( mVcnContext, template, mCellNetworkRecord, SUB_GROUP, - mSubscriptionSnapshot)); + mSubscriptionSnapshot, + null /* currentlySelected */, + null /* carrierConfig */)); } @Test From 60d1547e8e10901eb388ebbf1a3b7fe5433be9a9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 24 Mar 2023 15:45:08 -0700 Subject: [PATCH 0371/1057] Refactor VCN network selection CTS This is a preparation commit that creates sharing methods that allow the followup commit to add network selection tests based on carrier capabilities. Bug: 263415068 Test: atest VcnManagerTest Change-Id: I9960aead20eea4377d1efef613d781e85f1c5da3 --- .../android/net/vcn/cts/VcnManagerTest.java | 225 +++++++++++------- 1 file changed, 139 insertions(+), 86 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 6051a5c7a0..8de86d3f8b 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -519,6 +519,128 @@ public class VcnManagerTest extends VcnTestBase { } } + private class NetworkSelectionTestNetworkParams { + public final boolean isMetered; + + NetworkSelectionTestNetworkParams(boolean isMetered) { + this.isMetered = isMetered; + } + } + + private TestNetworkWrapper createTestNetworkForNetworkSelection( + int subId, NetworkSelectionTestNetworkParams params) throws Exception { + return createTestNetworkWrapper(params.isMetered, subId, LOCAL_ADDRESS); + } + + private void verifyVcnMigratesToPreferredUnderlyingNetwork( + VcnConfig vcnConfig, + NetworkSelectionTestNetworkParams lessPreferred, + NetworkSelectionTestNetworkParams preferred) + throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + // Start on a less preferred network. + try (TestNetworkWrapper testNetworkWrapperLessPreferred = + createTestNetworkForNetworkSelection(subId, lessPreferred)) { + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperLessPreferred); + + // Then bring up a more preferred network, and expect to switch to it. + try (TestNetworkWrapper testNetworkWrapperPreferred = + createTestNetworkForNetworkSelection(subId, preferred)) { + injectAndVerifyIkeMobikePackets( + testNetworkWrapperPreferred.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + + private void verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( + VcnConfig vcnConfig, + NetworkSelectionTestNetworkParams lessPreferred, + NetworkSelectionTestNetworkParams preferred) + throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + // Start on a more preferred network. + try (TestNetworkWrapper testNetworkWrapperPreferred = + createTestNetworkForNetworkSelection(subId, preferred)) { + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperPreferred); + + // Then bring up a less preferred network, and expect the VCN underlying + // network does not change. + try (TestNetworkWrapper testNetworkWrapperLessPreferred = + createTestNetworkForNetworkSelection(subId, lessPreferred)) { + injectAndVerifyIkeDpdPackets( + testNetworkWrapperPreferred.ikeTunUtils, + vcnSetupResult.ikeExchangePortPair); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + + private void verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( + VcnConfig vcnConfig, + NetworkSelectionTestNetworkParams lessPreferred, + NetworkSelectionTestNetworkParams preferred) + throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + // Start on a more preferred network + try (TestNetworkWrapper testNetworkWrapperPreferred = + createTestNetworkForNetworkSelection(subId, preferred)) { + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + testNetworkWrapperPreferred); + + // Bring up a less preferred network + try (TestNetworkWrapper testNetworkWrapperLessPreferred = + createTestNetworkForNetworkSelection(subId, lessPreferred)) { + // Teardown the preferred network + testNetworkWrapperPreferred.close(); + testNetworkWrapperPreferred.vcnNetworkCallback.waitForLost(); + + // Verify the VCN switches to the remaining less preferred network + injectAndVerifyIkeMobikePackets( + testNetworkWrapperLessPreferred.ikeTunUtils); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + } + }); + } + } + private VcnConfig createVcnConfigPrefersMetered() throws Exception { final List nwTemplates = new ArrayList<>(); nwTemplates.add( @@ -529,98 +651,29 @@ public class VcnManagerTest extends VcnTestBase { } @Test - public void testVcnMigratesToPreferredUnderlyingNetwork() throws Exception { - final int subId = verifyAndGetValidDataSubId(); - final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); - - // Start on NOT_METERED, less preferred network. - try (TestNetworkWrapper testNetworkWrapperNotMetered = - createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { - verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final VcnSetupResult vcnSetupResult = - setupAndGetVcnNetwork( - subGrp, - cellNetwork, - cellNetworkCb, - vcnConfig, - testNetworkWrapperNotMetered); - - // Then bring up a more preferred network, and expect to switch to it. - try (TestNetworkWrapper testNetworkWrapperMetered = - createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { - injectAndVerifyIkeMobikePackets(testNetworkWrapperMetered.ikeTunUtils); - - clearVcnConfigsAndVerifyNetworkTeardown( - subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); - } - }); - } + public void testVcnMigratesToPreferredUnderlyingNetwork_preferMetered() throws Exception { + verifyVcnMigratesToPreferredUnderlyingNetwork( + createVcnConfigPrefersMetered(), + new NetworkSelectionTestNetworkParams(false /* isMetered */), + new NetworkSelectionTestNetworkParams(true /* isMetered */)); } @Test - public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork() throws Exception { - final int subId = verifyAndGetValidDataSubId(); - final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); - - // Start on METERED, more preferred network - try (TestNetworkWrapper testNetworkWrapperMetered = - createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { - verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final VcnSetupResult vcnSetupResult = - setupAndGetVcnNetwork( - subGrp, - cellNetwork, - cellNetworkCb, - vcnConfig, - testNetworkWrapperMetered); - - // Then bring up a less preferred network, and expect the VCN underlying - // network does not change. - try (TestNetworkWrapper testNetworkWrapperNotMetered = - createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { - injectAndVerifyIkeDpdPackets( - testNetworkWrapperMetered.ikeTunUtils, - vcnSetupResult.ikeExchangePortPair); - - clearVcnConfigsAndVerifyNetworkTeardown( - subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); - } - }); - } + public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferMetered() + throws Exception { + verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( + createVcnConfigPrefersMetered(), + new NetworkSelectionTestNetworkParams(false /* isMetered */), + new NetworkSelectionTestNetworkParams(true /* isMetered */)); } @Test - public void testVcnMigratesAfterPreferredUnderlyingNetworkDies() throws Exception { - final int subId = verifyAndGetValidDataSubId(); - final VcnConfig vcnConfig = createVcnConfigPrefersMetered(); - - // Start on METERED, more preferred network - try (TestNetworkWrapper testNetworkWrapperMetered = - createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { - verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { - final VcnSetupResult vcnSetupResult = - setupAndGetVcnNetwork( - subGrp, - cellNetwork, - cellNetworkCb, - vcnConfig, - testNetworkWrapperMetered); - - // Bring up a NOT_METERED, less preferred network - try (TestNetworkWrapper testNetworkWrapperNotMetered = - createTestNetworkWrapper(false /* isMetered */, subId, LOCAL_ADDRESS)) { - // Teardown the preferred network - testNetworkWrapperMetered.close(); - testNetworkWrapperMetered.vcnNetworkCallback.waitForLost(); - - // Verify the VCN switches to the remaining NOT_METERED network - injectAndVerifyIkeMobikePackets(testNetworkWrapperNotMetered.ikeTunUtils); - - clearVcnConfigsAndVerifyNetworkTeardown( - subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); - } - }); - } + public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferMetered() + throws Exception { + verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( + createVcnConfigPrefersMetered(), + new NetworkSelectionTestNetworkParams(false /* isMetered */), + new NetworkSelectionTestNetworkParams(true /* isMetered */)); } @Test From 32856931c356c6db8c0f30f83087a200d176221f Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 24 Mar 2023 20:55:16 +0000 Subject: [PATCH 0372/1057] Match underlying networks based on interface name This patch changes the VcnManagementService policy matching from using capabilities to match against underlying networks to using iface names. This is significantly more precise than the network capability matching logic, as that will not catch any new capabilities that were added (eg ENTERPRISE, LOW_LATENCY, HIGH_BANDWIDTH, etc). Bug: 274861645 Test: atest FrameworksVcnTests CtsVcnTestCases Change-Id: Iea2f5afb242649517f83f85c77355cfdbbf1e202 --- .../android/server/VcnManagementService.java | 36 ++++++++--- .../server/VcnManagementServiceTest.java | 64 ++++++++++++++++--- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index f652cb050c..78d4708e70 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -1104,7 +1104,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final NetworkCapabilities result = ncBuilder.build(); final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback - .requiresRestartForImmutableCapabilityChanges(result), + .requiresRestartForImmutableCapabilityChanges(result, linkProperties), result); logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities @@ -1354,19 +1354,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { * without requiring a Network restart. */ private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback { + private final Object mLockObject = new Object(); private final Map mCaps = new ArrayMap<>(); + private final Map mLinkProperties = new ArrayMap<>(); @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) { - synchronized (mCaps) { + synchronized (mLockObject) { mCaps.put(network, caps); } } + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties lp) { + synchronized (mLockObject) { + mLinkProperties.put(network, lp); + } + } + @Override public void onLost(Network network) { - synchronized (mCaps) { + synchronized (mLockObject) { mCaps.remove(network); + mLinkProperties.remove(network); } } @@ -1393,22 +1403,28 @@ public class VcnManagementService extends IVcnManagementService.Stub { return true; } - private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) { + private boolean requiresRestartForImmutableCapabilityChanges( + NetworkCapabilities caps, LinkProperties lp) { if (caps.getSubscriptionIds() == null) { return false; } - synchronized (mCaps) { - for (NetworkCapabilities existing : mCaps.values()) { - if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds()) - && hasSameTransportsAndCapabilities(caps, existing)) { - // Restart if any immutable capabilities have changed - return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + synchronized (mLockObject) { + // Search for an existing network (using interfce names) + // TODO: Get network from NetworkFactory (if exists) for this match. + for (Entry lpEntry : mLinkProperties.entrySet()) { + if (lp.getInterfaceName() != null + && !lp.getInterfaceName().isEmpty() + && Objects.equals( + lp.getInterfaceName(), lpEntry.getValue().getInterfaceName())) { + return mCaps.get(lpEntry.getKey()) + .hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); } } } + // If no network found, by definition does not need restart. return false; } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 075bc5e521..4123f8070e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -17,7 +17,9 @@ package com.android.server; import static android.net.ConnectivityManager.NetworkCallback; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -67,7 +69,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.TelephonyNetworkSpecifier; import android.net.Uri; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -128,6 +129,15 @@ public class VcnManagementServiceTest { private static final VcnConfig TEST_VCN_CONFIG; private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final int TEST_UID = Process.FIRST_APPLICATION_UID; + private static final String TEST_IFACE_NAME = "TEST_IFACE"; + private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2"; + private static final LinkProperties TEST_LP_1 = new LinkProperties(); + private static final LinkProperties TEST_LP_2 = new LinkProperties(); + + static { + TEST_LP_1.setInterfaceName(TEST_IFACE_NAME); + TEST_LP_2.setInterfaceName(TEST_IFACE_NAME_2); + } static { final Context mockConfigContext = mock(Context.class); @@ -1034,8 +1044,7 @@ public class VcnManagementServiceTest { setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); return mVcnMgmtSvc.getUnderlyingNetworkPolicy( - getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), - new LinkProperties()); + getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), TEST_LP_1); } private void checkGetRestrictedTransportsFromCarrierConfig( @@ -1260,7 +1269,7 @@ public class VcnManagementServiceTest { false /* expectRestricted */); } - private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { + private void setupTrackedNetwork(NetworkCapabilities caps, LinkProperties lp) { mVcnMgmtSvc.systemReady(); final ArgumentCaptor captor = @@ -1269,7 +1278,10 @@ public class VcnManagementServiceTest { .registerNetworkCallback( eq(new NetworkRequest.Builder().clearCapabilities().build()), captor.capture()); - captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps); + + Network mockNetwork = mock(Network.class, CALLS_REAL_METHODS); + captor.getValue().onCapabilitiesChanged(mockNetwork, caps); + captor.getValue().onLinkPropertiesChanged(mockNetwork, lp); } @Test @@ -1279,7 +1291,7 @@ public class VcnManagementServiceTest { getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED // immutable capability @@ -1288,7 +1300,7 @@ public class VcnManagementServiceTest { getNetworkCapabilitiesBuilderForTransport( TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .build(), - new LinkProperties()); + TEST_LP_1); assertTrue(policy.isTeardownRequested()); } @@ -1298,7 +1310,7 @@ public class VcnManagementServiceTest { final NetworkCapabilities existingNetworkCaps = getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); final VcnUnderlyingNetworkPolicy policy = startVcnAndGetPolicyForTransport( @@ -1315,7 +1327,7 @@ public class VcnManagementServiceTest { .addCapability(NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NET_CAPABILITY_IMS) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); final VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy( @@ -1336,7 +1348,7 @@ public class VcnManagementServiceTest { new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2)) + .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2)) .build(); VcnUnderlyingNetworkPolicy policy = @@ -1346,6 +1358,38 @@ public class VcnManagementServiceTest { assertEquals(nc, policy.getMergedNetworkCapabilities()); } + /** + * Checks that networks with similar capabilities do not clobber each other. + * + *

    In previous iterations, the VcnMgmtSvc used capability-matching to check if a network + * undergoing policy checks were the same as an existing networks. However, this meant that if + * there were newly added capabilities that the VCN did not check, two networks differing only + * by that capability would restart each other constantly. + */ + @Test + public void testGetUnderlyingNetworkPolicySimilarNetworks() throws Exception { + NetworkCapabilities nc1 = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .addCapability(NET_CAPABILITY_INTERNET) + .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2)) + .build(); + + NetworkCapabilities nc2 = + new NetworkCapabilities.Builder(nc1) + .addCapability(NET_CAPABILITY_ENTERPRISE) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(); + + setupTrackedNetwork(nc1, TEST_LP_1); + + VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc2, TEST_LP_2); + + assertFalse(policy.isTeardownRequested()); + assertEquals(nc2, policy.getMergedNetworkCapabilities()); + } + @Test(expected = SecurityException.class) public void testGetUnderlyingNetworkPolicyInvalidPermission() { doReturn(PackageManager.PERMISSION_DENIED) From 852d08db17b90fa04075a687f9250783e27586f9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 17 Mar 2023 19:34:04 +0000 Subject: [PATCH 0373/1057] Add VCN CTS to verify network selection based on capabilities This commit extends the existing network selection tests to also cover selection based on capabilities. It also verifies that VCN can be built on a non-Internet network. Additionally, this commit removes capabilities that are not allowed on a test network from the TestNetworkWrapper since those capabilities will be removed by the ConnectivityService anyway. Bug: 263415068 Test: atest VcnManagerTest (new tests) Change-Id: Ibba855647d3b391ac94670b3672076c1fbb3fc61 --- .../net/vcn/cts/TestNetworkWrapper.java | 14 +- .../android/net/vcn/cts/VcnManagerTest.java | 182 ++++++++++++++---- 2 files changed, 153 insertions(+), 43 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index d70cc2b168..e1a2fd0004 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -99,7 +99,7 @@ public class TestNetworkWrapper implements AutoCloseable { public TestNetworkWrapper( @NonNull Context context, int mtu, - boolean isMetered, + @NonNull Set capabilities, @NonNull Set subIds, @NonNull InetAddress localAddress) throws Exception { @@ -125,7 +125,7 @@ public class TestNetworkWrapper implements AutoCloseable { mConnectivityManager.requestNetwork(nr, vcnNetworkCallback); final NetworkCapabilities nc = - createNetworkCapabilitiesForIface(iface, isMetered, subIds); + createNetworkCapabilitiesForIface(iface, capabilities, subIds); final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); final VcnNetworkPolicyResult policy = mVcnManager.applyVcnNetworkPolicy(nc, lp); @@ -150,21 +150,19 @@ public class TestNetworkWrapper implements AutoCloseable { } private static NetworkCapabilities createNetworkCapabilitiesForIface( - @NonNull String iface, boolean isMetered, Set subIds) { + @NonNull String iface, Set capabilities, Set subIds) { NetworkCapabilities.Builder builder = NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) - .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) - .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA) .setNetworkSpecifier(new TestNetworkSpecifier(iface)) .setSubscriptionIds(subIds); - if (!isMetered) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + for (int cap : capabilities) { + builder.addCapability(cap); } + return builder.build(); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 8de86d3f8b..eba8a0327e 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -19,11 +19,14 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -51,6 +54,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; @@ -77,7 +81,9 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -364,18 +370,29 @@ public class VcnManagerTest extends VcnTestBase { } private TestNetworkWrapper createTestNetworkWrapper( - boolean isMetered, int subId, InetAddress localAddress) throws Exception { + int subId, InetAddress localAddress, Set capabilities) throws Exception { TestNetworkWrapper testNetworkWrapper = new TestNetworkWrapper( mContext, TEST_NETWORK_MTU, - isMetered, + capabilities, Collections.singleton(subId), localAddress); assertNotNull("No test network found", testNetworkWrapper.tunNetwork); return testNetworkWrapper; } + private TestNetworkWrapper createTestNetworkWrapper( + boolean isMetered, int subId, InetAddress localAddress) throws Exception { + final Set capabilities = new HashSet<>(); + capabilities.add(NET_CAPABILITY_CBS); + if (!isMetered) { + capabilities.add(NET_CAPABILITY_NOT_METERED); + } + + return createTestNetworkWrapper(subId, localAddress, capabilities); + } + @Test public void testVcnManagedNetworkLosesNotVcnManagedCapability() throws Exception { final int subId = verifyAndGetValidDataSubId(); @@ -519,29 +536,19 @@ public class VcnManagerTest extends VcnTestBase { } } - private class NetworkSelectionTestNetworkParams { - public final boolean isMetered; - - NetworkSelectionTestNetworkParams(boolean isMetered) { - this.isMetered = isMetered; - } - } - private TestNetworkWrapper createTestNetworkForNetworkSelection( - int subId, NetworkSelectionTestNetworkParams params) throws Exception { - return createTestNetworkWrapper(params.isMetered, subId, LOCAL_ADDRESS); + int subId, Set capabilities) throws Exception { + return createTestNetworkWrapper(subId, LOCAL_ADDRESS, capabilities); } private void verifyVcnMigratesToPreferredUnderlyingNetwork( - VcnConfig vcnConfig, - NetworkSelectionTestNetworkParams lessPreferred, - NetworkSelectionTestNetworkParams preferred) + VcnConfig vcnConfig, Set capSetLessPreferred, Set capSetPreferred) throws Exception { final int subId = verifyAndGetValidDataSubId(); // Start on a less preferred network. try (TestNetworkWrapper testNetworkWrapperLessPreferred = - createTestNetworkForNetworkSelection(subId, lessPreferred)) { + createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) { verifyUnderlyingCellAndRunTest( subId, (subGrp, cellNetwork, cellNetworkCb) -> { @@ -555,7 +562,7 @@ public class VcnManagerTest extends VcnTestBase { // Then bring up a more preferred network, and expect to switch to it. try (TestNetworkWrapper testNetworkWrapperPreferred = - createTestNetworkForNetworkSelection(subId, preferred)) { + createTestNetworkForNetworkSelection(subId, capSetPreferred)) { injectAndVerifyIkeMobikePackets( testNetworkWrapperPreferred.ikeTunUtils); @@ -567,15 +574,13 @@ public class VcnManagerTest extends VcnTestBase { } private void verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( - VcnConfig vcnConfig, - NetworkSelectionTestNetworkParams lessPreferred, - NetworkSelectionTestNetworkParams preferred) + VcnConfig vcnConfig, Set capSetLessPreferred, Set capSetPreferred) throws Exception { final int subId = verifyAndGetValidDataSubId(); // Start on a more preferred network. try (TestNetworkWrapper testNetworkWrapperPreferred = - createTestNetworkForNetworkSelection(subId, preferred)) { + createTestNetworkForNetworkSelection(subId, capSetPreferred)) { verifyUnderlyingCellAndRunTest( subId, (subGrp, cellNetwork, cellNetworkCb) -> { @@ -590,7 +595,7 @@ public class VcnManagerTest extends VcnTestBase { // Then bring up a less preferred network, and expect the VCN underlying // network does not change. try (TestNetworkWrapper testNetworkWrapperLessPreferred = - createTestNetworkForNetworkSelection(subId, lessPreferred)) { + createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) { injectAndVerifyIkeDpdPackets( testNetworkWrapperPreferred.ikeTunUtils, vcnSetupResult.ikeExchangePortPair); @@ -603,15 +608,13 @@ public class VcnManagerTest extends VcnTestBase { } private void verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( - VcnConfig vcnConfig, - NetworkSelectionTestNetworkParams lessPreferred, - NetworkSelectionTestNetworkParams preferred) + VcnConfig vcnConfig, Set capSetLessPreferred, Set capSetPreferred) throws Exception { final int subId = verifyAndGetValidDataSubId(); // Start on a more preferred network try (TestNetworkWrapper testNetworkWrapperPreferred = - createTestNetworkForNetworkSelection(subId, preferred)) { + createTestNetworkForNetworkSelection(subId, capSetPreferred)) { verifyUnderlyingCellAndRunTest( subId, (subGrp, cellNetwork, cellNetworkCb) -> { @@ -625,7 +628,7 @@ public class VcnManagerTest extends VcnTestBase { // Bring up a less preferred network try (TestNetworkWrapper testNetworkWrapperLessPreferred = - createTestNetworkForNetworkSelection(subId, lessPreferred)) { + createTestNetworkForNetworkSelection(subId, capSetLessPreferred)) { // Teardown the preferred network testNetworkWrapperPreferred.close(); testNetworkWrapperPreferred.vcnNetworkCallback.waitForLost(); @@ -641,12 +644,23 @@ public class VcnManagerTest extends VcnTestBase { } } + private VcnCellUnderlyingNetworkTemplate.Builder createCellTemplateBaseBuilder() + throws Exception { + return new VcnCellUnderlyingNetworkTemplate.Builder().setInternet(MATCH_ANY); + } + private VcnConfig createVcnConfigPrefersMetered() throws Exception { final List nwTemplates = new ArrayList<>(); nwTemplates.add( - new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_REQUIRED).build()); + createCellTemplateBaseBuilder() + .setCbs(MATCH_REQUIRED) + .setMetered(MATCH_REQUIRED) + .build()); nwTemplates.add( - new VcnWifiUnderlyingNetworkTemplate.Builder().setMetered(MATCH_FORBIDDEN).build()); + createCellTemplateBaseBuilder() + .setCbs(MATCH_REQUIRED) + .setMetered(MATCH_FORBIDDEN) + .build()); return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); } @@ -654,8 +668,8 @@ public class VcnManagerTest extends VcnTestBase { public void testVcnMigratesToPreferredUnderlyingNetwork_preferMetered() throws Exception { verifyVcnMigratesToPreferredUnderlyingNetwork( createVcnConfigPrefersMetered(), - new NetworkSelectionTestNetworkParams(false /* isMetered */), - new NetworkSelectionTestNetworkParams(true /* isMetered */)); + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_CBS)); } @Test @@ -663,8 +677,8 @@ public class VcnManagerTest extends VcnTestBase { throws Exception { verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( createVcnConfigPrefersMetered(), - new NetworkSelectionTestNetworkParams(false /* isMetered */), - new NetworkSelectionTestNetworkParams(true /* isMetered */)); + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_CBS)); } @Test @@ -672,8 +686,106 @@ public class VcnManagerTest extends VcnTestBase { throws Exception { verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( createVcnConfigPrefersMetered(), - new NetworkSelectionTestNetworkParams(false /* isMetered */), - new NetworkSelectionTestNetworkParams(true /* isMetered */)); + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_CBS)); + } + + private VcnConfig createVcnConfigPrefersCbs() throws Exception { + final List nwTemplates = new ArrayList<>(); + nwTemplates.add(createCellTemplateBaseBuilder().setCbs(MATCH_REQUIRED).build()); + nwTemplates.add(createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).build()); + + return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + } + + @Test + public void testVcnMigratesToPreferredUnderlyingNetwork_preferCbs() throws Exception { + verifyVcnMigratesToPreferredUnderlyingNetwork( + createVcnConfigPrefersCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS)); + } + + @Test + public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferCbs() throws Exception { + verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( + createVcnConfigPrefersCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS)); + } + + @Test + public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferCbs() throws Exception { + verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( + createVcnConfigPrefersCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_CBS)); + } + + private VcnConfig createVcnConfigPrefersNonCbs() throws Exception { + final List nwTemplates = new ArrayList<>(); + nwTemplates.add( + createCellTemplateBaseBuilder() + .setRcs(MATCH_REQUIRED) + .setCbs(MATCH_FORBIDDEN) + .build()); + nwTemplates.add( + createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build()); + + return buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + } + + @Test + public void testVcnMigratesToPreferredUnderlyingNetwork_preferNonCbs() throws Exception { + verifyVcnMigratesToPreferredUnderlyingNetwork( + createVcnConfigPrefersNonCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS)); + } + + @Test + public void testVcnDoesNotSelectLessPreferredUnderlyingNetwork_preferNonCbs() throws Exception { + verifyVcnDoesNotSelectLessPreferredUnderlyingNetwork( + createVcnConfigPrefersNonCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS)); + } + + @Test + public void testVcnMigratesAfterPreferredUnderlyingNetworkDies_preferNonCbs() throws Exception { + verifyVcnMigratesAfterPreferredUnderlyingNetworkDies( + createVcnConfigPrefersNonCbs(), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS)); + } + + @Test + public void testSetVcnWithCbsMatchAny_preferCbsNetworkOverUnmatchedNetwork() throws Exception { + final List nwTemplates = new ArrayList<>(); + nwTemplates.add( + createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build()); + + final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + + verifyVcnMigratesToPreferredUnderlyingNetwork( + vcnConfig, + Set.of(NET_CAPABILITY_NOT_METERED), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS, NET_CAPABILITY_CBS)); + } + + @Test + public void testSetVcnWithCbsMatchAny_preferNonCbsNetworkOverUnmatchedNetwork() + throws Exception { + final List nwTemplates = new ArrayList<>(); + nwTemplates.add( + createCellTemplateBaseBuilder().setRcs(MATCH_REQUIRED).setCbs(MATCH_ANY).build()); + + final VcnConfig vcnConfig = buildVcnConfigBase(nwTemplates).setIsTestModeProfile().build(); + + verifyVcnMigratesToPreferredUnderlyingNetwork( + vcnConfig, + Set.of(NET_CAPABILITY_NOT_METERED), + Set.of(NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_RCS)); } @Test From cb77e78383b327eaa7818bb15cf12797546d110a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 18 Mar 2023 00:17:22 +0000 Subject: [PATCH 0374/1057] CTS to verify VCN can restrict networks based on transport type Bug: 263415068 Test: atest VcnManagerTest(new tests) Change-Id: Ia73bf84ebd70ef5effcca0d2189ebb6e791b65c6 --- .../net/vcn/cts/TestNetworkWrapper.java | 21 +- .../android/net/vcn/cts/VcnManagerTest.java | 188 ++++++++++++++++++ 2 files changed, 206 insertions(+), 3 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index e1a2fd0004..fb67b3e78a 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -54,6 +54,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -66,6 +67,7 @@ public class TestNetworkWrapper implements AutoCloseable { private static final String POLICY_LISTENER_TAG = TestNetworkAgent.TestVcnNetworkPolicyChangeListener.class.getSimpleName(); + private static final int POLICY_CHANGE_TIMEOUT_MS = 500; public static final int NETWORK_CB_TIMEOUT_MS = 5000; private static final int IP4_PREFIX_LEN = 32; @@ -124,6 +126,7 @@ public class TestNetworkWrapper implements AutoCloseable { vcnNetworkCallback = new VcnTestNetworkCallback(); mConnectivityManager.requestNetwork(nr, vcnNetworkCallback); + // Build TestNetworkAgent final NetworkCapabilities nc = createNetworkCapabilitiesForIface(iface, capabilities, subIds); final LinkProperties lp = createLinkPropertiesForIface(iface, mtu); @@ -155,7 +158,6 @@ public class TestNetworkWrapper implements AutoCloseable { NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) .setNetworkSpecifier(new TestNetworkSpecifier(iface)) .setSubscriptionIds(subIds); @@ -256,6 +258,10 @@ public class TestNetworkWrapper implements AutoCloseable { close(); } + public VcnNetworkPolicyResult awaitVcnNetworkPolicyChange() throws Exception { + return mTestNetworkAgent.mPolicyListener.awaitPolicyChange(); + } + /** * Test-only NetworkAgent to be used for instrumented TUN Networks. * @@ -263,7 +269,7 @@ public class TestNetworkWrapper implements AutoCloseable { */ private class TestNetworkAgent extends NetworkAgent { private final CloseGuard mCloseGuard = new CloseGuard(); - private final VcnNetworkPolicyChangeListener mPolicyListener = + private final TestVcnNetworkPolicyChangeListener mPolicyListener = new TestVcnNetworkPolicyChangeListener(); private final LinkProperties mLinkProperties; @@ -328,7 +334,10 @@ public class TestNetworkWrapper implements AutoCloseable { return mLinkProperties; } - private class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { + public class TestVcnNetworkPolicyChangeListener implements VcnNetworkPolicyChangeListener { + private final CompletableFuture mFutureOnPolicyChanged = + new CompletableFuture<>(); + @Override public void onPolicyChanged() { synchronized (TestNetworkAgent.this) { @@ -336,6 +345,8 @@ public class TestNetworkWrapper implements AutoCloseable { mVcnManager.applyVcnNetworkPolicy( mTestNetworkAgent.getNetworkCapabilities(), mTestNetworkAgent.getLinkProperties()); + + mFutureOnPolicyChanged.complete(policy); if (policy.isTeardownRequested()) { Log.w(POLICY_LISTENER_TAG, "network teardown requested on policy change"); teardown(); @@ -345,6 +356,10 @@ public class TestNetworkWrapper implements AutoCloseable { updateNetworkCapabilities(policy.getNetworkCapabilities()); } } + + public VcnNetworkPolicyResult awaitPolicyChange() throws Exception { + return mFutureOnPolicyChanged.get(POLICY_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index eba8a0327e..25466ee75c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -21,10 +21,12 @@ import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; @@ -41,6 +43,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; 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; @@ -57,6 +60,7 @@ import android.net.NetworkRequest; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager; +import android.net.vcn.VcnNetworkPolicyResult; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback; @@ -269,6 +273,190 @@ public class VcnManagerTest extends VcnTestBase { android.Manifest.permission.MANAGE_TEST_NETWORKS); } + private TestNetworkWrapper createTestNetworkWrapperForPolicyTest( + boolean isRestricted, int subId) throws Exception { + final Set capabilities = new HashSet<>(); + capabilities.add(NET_CAPABILITY_CBS); + if (!isRestricted) { + capabilities.add(NET_CAPABILITY_NOT_RESTRICTED); + } + + return createTestNetworkWrapper(subId, LOCAL_ADDRESS, capabilities); + } + + private VcnConfig buildVcnConfigWithTransportTestRestricted() { + return buildVcnConfigBase() + .setIsTestModeProfile() + .setRestrictedUnderlyingNetworkTransports(Set.of(TRANSPORT_TEST)) + .build(); + } + + @Test + public void testApplyVcnNetworkPolicyDuringVcnSetup_onUnrestrictedNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted(); + + try (TestNetworkWrapper networkWrapperUnrestricted = + createTestNetworkWrapperForPolicyTest(false /* isRestricted */, subId)) { + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + cellNetworkCb.waitForAvailable(); + + // Attempt VCN setup on an unrestricted network; expect the network to + // change to be restricted + mVcnManager.setVcnConfig(subGrp, vcnConfig); + + VcnNetworkPolicyResult policyResult = + networkWrapperUnrestricted.awaitVcnNetworkPolicyChange(); + + // Expect teardown due to restriction capability change + assertTrue(policyResult.isTeardownRequested()); + assertFalse( + policyResult + .getNetworkCapabilities() + .hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + + // Verify underlying network is lost + networkWrapperUnrestricted.vcnNetworkCallback.waitForLost(); + + mVcnManager.clearVcnConfig(subGrp); + }); + } + } + + @Test + public void testApplyVcnNetworkPolicyDuringVcnSetup_onRestrictedNetwork() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted(); + + try (TestNetworkWrapper networkWrapperRestricted = + createTestNetworkWrapperForPolicyTest(true /* isRestricted */, subId)) { + + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + // Set up VCN on a restricted network + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + networkWrapperRestricted); + + VcnNetworkPolicyResult policyResult = + networkWrapperRestricted.awaitVcnNetworkPolicyChange(); + + // Do not expect teardown since the restriction capability does not change + assertFalse(policyResult.isTeardownRequested()); + assertFalse( + policyResult + .getNetworkCapabilities() + .hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + }); + } + } + + private void waitForSafeMode(TestNetworkWrapper networkWrapper) throws Exception { + // Once VCN starts, the test network should lose NOT_VCN_MANAGED + waitForExpectedUnderlyingNetworkWithCapabilities( + networkWrapper, + false /* expectNotVcnManaged */, + false /* expectNotMetered */, + TestNetworkWrapper.NETWORK_CB_TIMEOUT_MS); + + // After VCN has started up, wait for safemode to kick in and expect the + // underlying Test Network to regain NOT_VCN_MANAGED. + waitForExpectedUnderlyingNetworkWithCapabilities( + networkWrapper, + true /* expectNotVcnManaged */, + false /* expectNotMetered */, + SAFEMODE_TIMEOUT_MILLIS); + } + + private void verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( + boolean isSafeMode, boolean isRestrictedBefore, boolean expectRestrictedAfter) + throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final VcnConfig vcnConfig = buildVcnConfigWithTransportTestRestricted(); + + try (TestNetworkWrapper networkWrapperRestricted = + createTestNetworkWrapperForPolicyTest(true /* isRestricted */, subId)) { + + verifyUnderlyingCellAndRunTest( + subId, + (subGrp, cellNetwork, cellNetworkCb) -> { + // Set up VCN on a restricted network + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork( + subGrp, + cellNetwork, + cellNetworkCb, + vcnConfig, + networkWrapperRestricted); + + if (isSafeMode) { + waitForSafeMode(networkWrapperRestricted); + } + + // Bring up another test network and verify its restriction capability + // change. + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapperForPolicyTest(isRestrictedBefore, subId)) { + + // The requested NetworkCapabilities should have been changed by + // VcnManager before the test network was brought up. Verify it by + // checking the NetworkCapabilities after the network setup. + final NetworkCapabilities nc = + mConnectivityManager.getNetworkCapabilities( + testNetworkWrapper.tunNetwork); + assertEquals( + !expectRestrictedAfter, + nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + } + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + }); + } + } + + @Test + public void testApplyVcnNetworkPolicy_activeMode_onRestrictedNetwork() throws Exception { + verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( + false /* isSafeMode */, + true /* isRestrictedBefore */, + true /* expectRestrictedAfter */); + } + + @Test + public void testApplyVcnNetworkPolicy_safeMode_onRestrictedNetwork() throws Exception { + verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( + true /* isSafeMode */, + true /* isRestrictedBefore */, + true /* expectRestrictedAfter */); + } + + @Test + public void testApplyVcnNetworkPolicy_activeMode_onUnrestrictedNetwork() throws Exception { + verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( + false /* isSafeMode */, + false /* isRestrictedBefore */, + true /* expectRestrictedAfter */); + } + + @Test + public void testApplyVcnNetworkPolicy_safeMode_onUnrestrictedNetwork() throws Exception { + verifyApplyVcnNetworkPolicyPostVcnSetupChangeNetworkRestriction( + true /* isSafeMode */, + false /* isRestrictedBefore */, + false /* expectRestrictedAfter */); + } + /** Test implementation of VcnStatusCallback for verification purposes. */ private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { private final CompletableFuture mFutureOnStatusChanged = From 422c6a72d6bd43b3e94922a407b6cc02a3e3daf4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 31 Jan 2023 01:38:17 +0000 Subject: [PATCH 0375/1057] VCN: Allow restricting TRANSPORT_TEST for CTS This commit updates VCN to be able to mark a test network as restricted. Additionally, when VCN is in safe mode, VCN will delegate to the Android system to decide the restriction policy of the test network. This commit allows CTS to verify VCN's ability of restricting networks based on the transport type. Bug: 263415068 Test: atest VcnManagerTest (new tests) Change-Id: I5fe0be4ce445a4d9c20cbef5ee4a2eb55403b3c8 --- .../src/android/net/vcn/VcnConfig.java | 7 ++++ .../android/server/VcnManagementService.java | 7 ++-- .../java/android/net/vcn/VcnConfigTest.java | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index 6f9c9dd918..a27e9230d4 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static com.android.internal.annotations.VisibleForTesting.Visibility; @@ -75,6 +76,7 @@ public final class VcnConfig implements Parcelable { static { ALLOWED_TRANSPORTS.add(TRANSPORT_WIFI); ALLOWED_TRANSPORTS.add(TRANSPORT_CELLULAR); + ALLOWED_TRANSPORTS.add(TRANSPORT_TEST); } private static final String PACKAGE_NAME_KEY = "mPackageName"; @@ -155,6 +157,11 @@ public final class VcnConfig implements Parcelable { + transport + " which might be from a new version of VcnConfig"); } + + if (transport == TRANSPORT_TEST && !mIsTestModeProfile) { + throw new IllegalArgumentException( + "Found TRANSPORT_TEST in a non-test-mode profile"); + } } } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 78d4708e70..e8c85ce68f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -1074,9 +1074,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { subGrp, mLastSnapshot, mConfigs.get(subGrp)); for (int restrictedTransport : restrictedTransports) { if (ncCopy.hasTransport(restrictedTransport)) { - if (restrictedTransport == TRANSPORT_CELLULAR) { - // Only make a cell network as restricted when the VCN is in - // active mode. + if (restrictedTransport == TRANSPORT_CELLULAR + || restrictedTransport == TRANSPORT_TEST) { + // For cell or test network, only mark it as restricted when + // the VCN is in active mode. isRestricted |= (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE); } else { isRestricted = true; diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java index b313c9fc6c..73a0a6183c 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnConfigTest.java @@ -17,6 +17,7 @@ package android.net.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertEquals; @@ -160,6 +161,37 @@ public class VcnConfigTest { assertNotEquals(config, configNotEqual); } + private VcnConfig buildConfigRestrictTransportTest(boolean isTestMode) throws Exception { + VcnConfig.Builder builder = + new VcnConfig.Builder(mContext) + .setRestrictedUnderlyingNetworkTransports(Set.of(TRANSPORT_TEST)); + if (isTestMode) { + builder.setIsTestModeProfile(); + } + + for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) { + builder.addGatewayConnectionConfig(gatewayConnectionConfig); + } + + return builder.build(); + } + + @Test + public void testRestrictTransportTestInTestModeProfile() throws Exception { + final VcnConfig config = buildConfigRestrictTransportTest(true /* isTestMode */); + assertEquals(Set.of(TRANSPORT_TEST), config.getRestrictedUnderlyingNetworkTransports()); + } + + @Test + public void testRestrictTransportTestInNonTestModeProfile() throws Exception { + try { + buildConfigRestrictTransportTest(false /* isTestMode */); + fail("Expected exception because the config is not a test mode profile"); + } catch (Exception expected) { + + } + } + @Test public void testParceling() { final VcnConfig config = buildTestConfig(mContext); From 8b0fde15a78697aa6af43ae72960c453bd070307 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 Apr 2023 06:29:44 +0000 Subject: [PATCH 0376/1057] Update VCN tests for Kernel MOBIKE This change updates the VCN tests to support Kernel MOBIKE, such that if the feature is enabled, there is no expectation that rekeys are sent out. The test already verifies that the new migrated transforms are applied properly, and data is transmitted over the new network. Bug: 179068694 Test: atest CtsVcnTestCases Change-Id: I9e0b630772398aeaf287f0ad485c506511a964d5 --- .../android/net/vcn/cts/VcnManagerTest.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 25466ee75c..70467e3f58 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -50,6 +50,7 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageManager; import android.ipsec.ike.cts.IkeTunUtils; import android.net.ConnectivityManager; import android.net.InetAddresses; @@ -1173,17 +1174,22 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */, ikeUpdateSaResp); - ikeTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 3 /* expectedMsgId */, - true /* expectedUseEncap */, - ikeCreateChildResp); + // If Kernel migration enabled, it will be used instead of MOBIKE-rekey + // TODO (b/277939911): Decouple VCN CTS from IKE implementation behavior + if (!mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION)) { + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 3 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeCreateChildResp); - ikeTunUtils.awaitReqAndInjectResp( - IKE_DETERMINISTIC_INITIATOR_SPI, - 4 /* expectedMsgId */, - true /* expectedUseEncap */, - ikeDeleteChildResp); + ikeTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 4 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeDeleteChildResp); + } } private void injectAndVerifyIkeDpdPackets( From 8aa16edaa2a78ce883f242ea498b4fd168a82d19 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 31 May 2023 18:21:58 +0000 Subject: [PATCH 0377/1057] Add attribution tags for VCN and VPN Allows IKE library metrics to identify and log the system clients Bug: 278943609 Test: manually verified the metrics Test: CtsVcnTestCases, FrameworksVcnTests, Ikev2VpnTest Change-Id: I4f1ad093ceeb762f4ee72be9bf00445e64d70793 --- .../src/com/android/server/VcnManagementService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e8c85ce68f..5f8b441e30 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -162,6 +162,8 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; + private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int LOCAL_LOG_LINE_COUNT = 512; @@ -223,7 +225,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { - mContext = requireNonNull(context, "Missing context"); + mContext = + requireNonNull(context, "Missing context") + .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); mDeps = requireNonNull(deps, "Missing dependencies"); mLooper = mDeps.getLooper(); From 54595cc6f2b601cec50fae23eabe5ccc9c425cb5 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 7 Jun 2023 08:46:51 +0000 Subject: [PATCH 0378/1057] Revert "Add attribution tags for VCN and VPN" This reverts commit 8aa16edaa2a78ce883f242ea498b4fd168a82d19. Reason for revert: Change-Id: I4665c257c3cca28f0f657ba0f653ba2068f0d5e2 --- .../src/com/android/server/VcnManagementService.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 5f8b441e30..e8c85ce68f 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -162,8 +162,6 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); - @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; - private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int LOCAL_LOG_LINE_COUNT = 512; @@ -225,9 +223,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { - mContext = - requireNonNull(context, "Missing context") - .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); + mContext = requireNonNull(context, "Missing context"); mDeps = requireNonNull(deps, "Missing dependencies"); mLooper = mDeps.getLooper(); From bfc0458ae0ce4f8d695c28d281c09444f4fa35b6 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 8 Jun 2023 02:07:53 +0000 Subject: [PATCH 0379/1057] Add a null pointer check to the VcnConfig Add a null pointer check before accessing the VcnConfig to retrieve the restricted transport types. Bug: 284381334 Test: atest CtsVcnTestCases, FrameworksVcnTestCases Change-Id: I0cbab6e38f68d8c669db2ddb324b013baa93204a --- .../src/com/android/server/VcnManagementService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e8c85ce68f..3efb6c304b 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -1065,13 +1065,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { boolean isRestricted = false; synchronized (mLock) { final Vcn vcn = mVcns.get(subGrp); + final VcnConfig vcnConfig = mConfigs.get(subGrp); if (vcn != null) { + if (vcnConfig == null) { + // TODO: b/284381334 Investigate for the root cause of this issue + // and handle it properly + logWtf("Vcn instance exists but VcnConfig does not for " + subGrp); + } + if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) { isVcnManagedNetwork = true; } final Set restrictedTransports = mDeps.getRestrictedTransports( - subGrp, mLastSnapshot, mConfigs.get(subGrp)); + subGrp, mLastSnapshot, vcnConfig); for (int restrictedTransport : restrictedTransports) { if (ncCopy.hasTransport(restrictedTransport)) { if (restrictedTransport == TRANSPORT_CELLULAR From 673f1e2becf47e8bc2f5bc2d94a6661a7573dccb Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 8 Jun 2023 02:07:53 +0000 Subject: [PATCH 0380/1057] Add a null pointer check to the VcnConfig Add a null pointer check before accessing the VcnConfig to retrieve the restricted transport types. Bug: 284381334 Test: atest CtsVcnTestCases, FrameworksVcnTestCases (cherry picked from https://android-review.googlesource.com/q/commit:bfc0458ae0ce4f8d695c28d281c09444f4fa35b6) Merged-In: I0cbab6e38f68d8c669db2ddb324b013baa93204a Change-Id: I0cbab6e38f68d8c669db2ddb324b013baa93204a --- .../src/com/android/server/VcnManagementService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e8c85ce68f..3efb6c304b 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -1065,13 +1065,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { boolean isRestricted = false; synchronized (mLock) { final Vcn vcn = mVcns.get(subGrp); + final VcnConfig vcnConfig = mConfigs.get(subGrp); if (vcn != null) { + if (vcnConfig == null) { + // TODO: b/284381334 Investigate for the root cause of this issue + // and handle it properly + logWtf("Vcn instance exists but VcnConfig does not for " + subGrp); + } + if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) { isVcnManagedNetwork = true; } final Set restrictedTransports = mDeps.getRestrictedTransports( - subGrp, mLastSnapshot, mConfigs.get(subGrp)); + subGrp, mLastSnapshot, vcnConfig); for (int restrictedTransport : restrictedTransports) { if (ncCopy.hasTransport(restrictedTransport)) { if (restrictedTransport == TRANSPORT_CELLULAR From 33d2f177917001b4fe8b08e7c727b4f1a98e4e30 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 31 May 2023 18:21:58 +0000 Subject: [PATCH 0381/1057] Reland: Add attribution tags for VCN and VPN Allows IKE library metrics to identify and log the system clients This commit also updates VcnManagementServiceTest to mock out createAttributionContext Bug: 278943609 Test: manually verified the metrics Test: CtsVcnTestCases, FrameworksVcnTests, Ikev2VpnTest, VpnManagerServiceTest, VpnTest Change-Id: I8b326de0484f9c97eb1b12f27a792c5ebf35ba1e --- .../src/com/android/server/VcnManagementService.java | 6 +++++- .../java/com/android/server/VcnManagementServiceTest.java | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e8c85ce68f..5f8b441e30 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -162,6 +162,8 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; + private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int LOCAL_LOG_LINE_COUNT = 512; @@ -223,7 +225,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { - mContext = requireNonNull(context, "Missing context"); + mContext = + requireNonNull(context, "Missing context") + .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); mDeps = requireNonNull(deps, "Missing dependencies"); mLooper = mDeps.getLooper(); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4123f8070e..960b57cb63 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -118,6 +118,7 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2"; @@ -177,6 +178,7 @@ public class VcnManagementServiceTest { 0 /* carrierId */, 0 /* profileClass */); + private final Context mMockContextWithoutAttributionTag = mock(Context.class); private final Context mMockContext = mock(Context.class); private final VcnManagementService.Dependencies mMockDeps = mock(VcnManagementService.Dependencies.class); @@ -202,6 +204,10 @@ public class VcnManagementServiceTest { private final IBinder mMockIBinder = mock(IBinder.class); public VcnManagementServiceTest() throws Exception { + doReturn(mMockContext) + .when(mMockContextWithoutAttributionTag) + .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); + setupSystemService( mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); setupSystemService( @@ -249,7 +255,7 @@ public class VcnManagementServiceTest { doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk(); setupMockedCarrierPrivilege(true); - mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + mVcnMgmtSvc = new VcnManagementService(mMockContextWithoutAttributionTag, mMockDeps); setupActiveSubscription(TEST_UUID_1); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); From 82338c16e64968911e0997f29d3d7aa3c6c0f28a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 31 May 2023 18:21:58 +0000 Subject: [PATCH 0382/1057] Reland: Add attribution tags for VCN and VPN Allows IKE library metrics to identify and log the system clients This commit also updates VcnManagementServiceTest to mock out createAttributionContext Bug: 278943609 Test: manually verified the metrics Test: CtsVcnTestCases, FrameworksVcnTests, Ikev2VpnTest, VpnManagerServiceTest, VpnTest Change-Id: I8b326de0484f9c97eb1b12f27a792c5ebf35ba1e Merged-In: I8b326de0484f9c97eb1b12f27a792c5ebf35ba1e --- .../src/com/android/server/VcnManagementService.java | 6 +++++- .../java/com/android/server/VcnManagementServiceTest.java | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index e8c85ce68f..5f8b441e30 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -162,6 +162,8 @@ import java.util.concurrent.TimeUnit; // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); + @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; + private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int LOCAL_LOG_LINE_COUNT = 512; @@ -223,7 +225,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) { - mContext = requireNonNull(context, "Missing context"); + mContext = + requireNonNull(context, "Missing context") + .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); mDeps = requireNonNull(deps, "Missing dependencies"); mLooper = mDeps.getLooper(); diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4123f8070e..960b57cb63 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -118,6 +118,7 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2"; @@ -177,6 +178,7 @@ public class VcnManagementServiceTest { 0 /* carrierId */, 0 /* profileClass */); + private final Context mMockContextWithoutAttributionTag = mock(Context.class); private final Context mMockContext = mock(Context.class); private final VcnManagementService.Dependencies mMockDeps = mock(VcnManagementService.Dependencies.class); @@ -202,6 +204,10 @@ public class VcnManagementServiceTest { private final IBinder mMockIBinder = mock(IBinder.class); public VcnManagementServiceTest() throws Exception { + doReturn(mMockContext) + .when(mMockContextWithoutAttributionTag) + .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); + setupSystemService( mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); setupSystemService( @@ -249,7 +255,7 @@ public class VcnManagementServiceTest { doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk(); setupMockedCarrierPrivilege(true); - mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps); + mVcnMgmtSvc = new VcnManagementService(mMockContextWithoutAttributionTag, mMockDeps); setupActiveSubscription(TEST_UUID_1); doReturn(mMockIBinder).when(mMockPolicyListener).asBinder(); From 4e71b17dbaec1e8a182e2f8a8f6d511f9aca115d Mon Sep 17 00:00:00 2001 From: Frank Feng Date: Thu, 15 Jun 2023 13:43:31 -0700 Subject: [PATCH 0383/1057] [DO NOT MERGE] Update AndroidManifest.xml in cts/ Remove: Bug: 267766325 Test: TH Change-Id: I680040aa6967385d9aa1ff9cbc8453c3c45cdc73 Merged-In: Ibdc2bab558d6eae9ca0a5953f04d21d027160d16 --- Vcn/tests/cts/AndroidManifest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..87525a14a6 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -35,8 +35,6 @@ - From 1c23b2427538a85f38973e2e4ee77e3f23248420 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 16 Jun 2023 22:23:41 +0000 Subject: [PATCH 0384/1057] VCN: Explicitly handle IAE from updating underlying network IpSecTunnelInterface#setUnderlyingNetwork will throw IAE when the underlying network is not functional and has null LinkProperties. This commit updates VCN to explicitly handle this exception, instead relying on the mechanism for handling all uncaught exceptions. Bug: 240112879 Test: atest CtsVcnTestCases & FrameworksVcnTests Change-Id: I2fdf1da542eb04d56a04e04c762f8c2c19828071 --- .../server/vcn/VcnGatewayConnection.java | 2 +- ...cnGatewayConnectionConnectedStateTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index a1ef537ff2..d480ddb092 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1889,7 +1889,7 @@ public class VcnGatewayConnection extends StateMachine { mIpSecManager.applyTunnelModeTransform( tunnelIface, IpSecManager.DIRECTION_FWD, transform); } - } catch (IOException e) { + } catch (IOException | IllegalArgumentException e) { logInfo("Transform application failed for network " + token, e); sessionLost(token, e); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 89271e1218..302af523a4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -42,6 +42,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -345,6 +346,33 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verify(mConnMgr).reportNetworkConnectivity(eq(mNetworkAgent.getNetwork()), eq(false)); } + @Test + public void testMigrationHandleFailure() throws Exception { + triggerChildOpened(); + mTestLooper.dispatchAll(); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); + + mGatewayConnection + .getUnderlyingNetworkControllerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + + final IkeSessionConnectionInfo newIkeConnectionInfo = + new IkeSessionConnectionInfo( + TEST_ADDR_V4, TEST_ADDR_V4_2, TEST_UNDERLYING_NETWORK_RECORD_2.network); + getIkeSessionCallback().onIkeSessionConnectionInfoChanged(newIkeConnectionInfo); + getChildSessionCallback() + .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); + + doThrow(new IllegalArgumentException("testMigrationHandleFailure")) + .when(mIpSecSvc) + .setNetworkForTunnelInterface(anyInt(), any(), any()); + + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + verify(mIkeSession).close(); + } + private void triggerChildOpened() { triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR); } From db35a023971c9190c4e6ba43306bac7458bda234 Mon Sep 17 00:00:00 2001 From: Michael Mikhail Date: Tue, 20 Jun 2023 22:38:47 +0000 Subject: [PATCH 0385/1057] Revert "[DO NOT MERGE] Update AndroidManifest.xml in cts/" This reverts commit 4e71b17dbaec1e8a182e2f8a8f6d511f9aca115d. Reason for revert: b/288148105 Change-Id: I7d2b5956530c18d3e2bd142f45520724fcd075a1 --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index 87525a14a6..ac0625cc5e 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -35,6 +35,8 @@ + From dbed914db67fd4470a36af16fbcc4c9bafd6c577 Mon Sep 17 00:00:00 2001 From: Frank Feng Date: Wed, 28 Jun 2023 16:30:39 +0000 Subject: [PATCH 0386/1057] Revert "[DO NOT MERGE] Update AndroidManifest.xml in cts/" This reverts commit 4e71b17dbaec1e8a182e2f8a8f6d511f9aca115d. Reason for revert: Try again with files fixed in ag/2643652 removed. Change-Id: If1331a5d08a8d3d06a69aaec269fe907e0df1c37 --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index 87525a14a6..ac0625cc5e 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -35,6 +35,8 @@ + From 7a09b61dc1ffb391ed3dcd01a0c17c640de44ad2 Mon Sep 17 00:00:00 2001 From: Frank Feng Date: Wed, 28 Jun 2023 23:29:54 +0000 Subject: [PATCH 0387/1057] Revert "Revert "[DO NOT MERGE] Update AndroidManifest.xml in cts/"" This reverts commit dbed914db67fd4470a36af16fbcc4c9bafd6c577. Reason for revert: Reverted the wrong change. Change-Id: I4fb9c65ba800efcad46c69be73ff5c556f232916 --- Vcn/tests/cts/AndroidManifest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..87525a14a6 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -35,8 +35,6 @@ - From 30d01d02da6fa30855e09c751eeb547cfd525e55 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 29 Jun 2023 23:45:38 +0000 Subject: [PATCH 0388/1057] Fix the bug component of VCN CTS Bug: 286591103 Test: no functional change Change-Id: Id95170238adc3dd6d7ff6e7f0c71a5047274634b --- Vcn/tests/cts/OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS index b3efc7bcc7..744d708137 100644 --- a/Vcn/tests/cts/OWNERS +++ b/Vcn/tests/cts/OWNERS @@ -1,3 +1,3 @@ -# Bug component: 685852 +# Bug component: 826680 nharold@google.com yangji@google.com \ No newline at end of file From 3c75218c32521d89cc9c41ac55faedb01362adca Mon Sep 17 00:00:00 2001 From: rambowang Date: Fri, 28 Jul 2023 22:42:16 +0000 Subject: [PATCH 0389/1057] Update TelephonySubscriptionTracker with new CarrierConfigManager APIs - Replace CarrierConfigChange receiver with listener - Get subset of carrier configs with new API instead of private method Bug: 265961787 Test: atest TelephonySubscriptionTrackerTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b4255755fbf631602db6065f7d55f27d6dc4badc) Merged-In: I93f14421624ac76bdf84c06cfd4c067bf2ccde7a Change-Id: I93f14421624ac76bdf84c06cfd4c067bf2ccde7a --- .../vcn/TelephonySubscriptionTracker.java | 38 ++++++------- .../vcn/TelephonySubscriptionTrackerTest.java | 53 ++++++++++--------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index ca4a32f553..099c9ae33b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -16,9 +16,6 @@ package com.android.server.vcn; -import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; @@ -48,7 +45,6 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.util.ArrayList; @@ -109,6 +105,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; + @NonNull + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (int logicalSlotIndex, int subscriptionId, int carrierId, int specificCarrierId) -> + handleActionCarrierConfigChanged(logicalSlotIndex, subscriptionId); + + public TelephonySubscriptionTracker( @NonNull Context context, @NonNull Handler handler, @@ -149,13 +151,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public void register() { final HandlerExecutor executor = new HandlerExecutor(mHandler); final IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); + mCarrierConfigManager.registerCarrierConfigChangeListener(executor, + mCarrierConfigChangeListener); registerCarrierPrivilegesCallbacks(); } @@ -197,6 +200,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); + mCarrierConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); unregisterCarrierPrivilegesCallbacks(); } @@ -273,7 +277,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } /** - * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED + * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED * *

    The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all * serialized on mHandler, avoiding the need for locking. @@ -281,9 +285,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { - case ACTION_CARRIER_CONFIG_CHANGED: - handleActionCarrierConfigChanged(context, intent); - break; case ACTION_MULTI_SIM_CONFIG_CHANGED: handleActionMultiSimConfigChanged(context, intent); break; @@ -310,26 +311,21 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { handleSubscriptionsChanged(); } - private void handleActionCarrierConfigChanged(Context context, Intent intent) { - // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it - // already was for an identified carrier, we can stop waiting for initial load to complete - final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); - final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); - + private void handleActionCarrierConfigChanged(int slotId, int subId) { if (slotId == INVALID_SIM_SLOT_INDEX) { return; } if (SubscriptionManager.isValidSubscriptionId(subId)) { - final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + // Get only configs as needed to save memory. + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) { mReadySubIdsBySlotId.put(slotId, subId); - final PersistableBundle minimized = - PersistableBundleUtils.minimizeBundle( - carrierConfig, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); - if (minimized != null) { - mSubIdToCarrierConfigMap.put(subId, new PersistableBundleWrapper(minimized)); + if (!carrierConfig.isEmpty()) { + mSubIdToCarrierConfigMap.put(subId, + new PersistableBundleWrapper(carrierConfig)); } handleSubscriptionsChanged(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 965b073ff0..34f884b942 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -19,9 +19,6 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; -import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; @@ -143,6 +140,8 @@ public class TelephonySubscriptionTrackerTest { @NonNull private TelephonySubscriptionTrackerCallback mCallback; @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker; + @NonNull private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; + public TelephonySubscriptionTrackerTest() { mContext = mock(Context.class); mTestLooper = new TestLooper(); @@ -173,7 +172,7 @@ public class TelephonySubscriptionTrackerTest { .getSystemService(Context.CARRIER_CONFIG_SERVICE); doReturn(TEST_CARRIER_CONFIG) .when(mCarrierConfigManager) - .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); // subId 1, 2 are in same subGrp, only subId 1 is active doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid(); @@ -189,9 +188,15 @@ public class TelephonySubscriptionTrackerTest { doReturn(2).when(mTelephonyManager).getActiveModemCount(); mCallback = mock(TelephonySubscriptionTrackerCallback.class); + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mTelephonySubscriptionTracker = new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); mTelephonySubscriptionTracker.register(); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any()); doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2)) @@ -239,14 +244,11 @@ public class TelephonySubscriptionTrackerTest { return intent; } - private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { - Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); - intent.putExtra( - EXTRA_SUBSCRIPTION_INDEX, - hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID); - - return intent; + private void sendCarrierConfigChange(boolean hasValidSubscription) { + mCarrierConfigChangeListener.onCarrierConfigChanged( + TEST_SIM_SLOT_INDEX, + hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( @@ -302,14 +304,15 @@ public class TelephonySubscriptionTrackerTest { any(), eq(mHandler)); final IntentFilter filter = getIntentFilter(); - assertEquals(2, filter.countActions()); - assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); + assertEquals(1, filter.countActions()); assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED)); verify(mSubscriptionManager) .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); assertNotNull(getOnSubscriptionsChangedListener()); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), any()); + verify(mTelephonyManager, times(2)) .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any()); verify(mTelephonyManager) @@ -442,7 +445,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); @@ -454,7 +457,7 @@ public class TelephonySubscriptionTrackerTest { .when(mSubscriptionManager) .getAllSubscriptionInfoList(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); // Expect an empty snapshot @@ -465,7 +468,7 @@ public class TelephonySubscriptionTrackerTest { public void testReceiveBroadcast_SlotCleared() throws Exception { setupReadySubIds(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + sendCarrierConfigChange(false /* hasValidSubscription */); mTestLooper.dispatchAll(); verifyNoActiveSubscriptions(); @@ -476,7 +479,7 @@ public class TelephonySubscriptionTrackerTest { public void testReceiveBroadcast_ConfigNotReady() throws Exception { doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any()); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); // No interactions expected; config was not loaded @@ -485,21 +488,21 @@ public class TelephonySubscriptionTrackerTest { @Test public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList(); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap()))); } @Test public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); reset(mCallback); @@ -510,12 +513,12 @@ public class TelephonySubscriptionTrackerTest { new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR}); doReturn(updatedConfig) .when(mCarrierConfigManager) - .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1)); + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); Map subIdToCarrierConfigMap = new HashMap<>(); subIdToCarrierConfigMap.put( TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig)); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback) @@ -530,13 +533,13 @@ public class TelephonySubscriptionTrackerTest { @Test public void testSlotClearedAfterValidTriggersCallbacks() throws Exception { - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); + sendCarrierConfigChange(true /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); assertNotNull( mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX)); - mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false)); + sendCarrierConfigChange(false /* hasValidSubscription */); mTestLooper.dispatchAll(); verify(mCallback) .onNewSnapshot( From abc258465ea51debf770e0442f546dceee41e08b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 11 Jul 2023 01:02:28 +0000 Subject: [PATCH 0390/1057] Deflake VCN teardown verification With this commit, the VCN test will clear the lost-network queue before tearing down the VCN network. This deflakes the test by removing other cell networks that have matched the NetworkRequest and then got disconnected. Bug: 290266134 Test: atest CtsVcnTestCases Test: brought up another physical cell network before setting up VCN and verified test passed Change-Id: Ie763b5f2e38c25a1bfcf9db3a2b713632bb9d187 --- .../cts/src/android/net/vcn/cts/TestNetworkWrapper.java | 4 ++++ Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index fb67b3e78a..60fe35cdbc 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -390,6 +390,10 @@ public class TestNetworkWrapper implements AutoCloseable { return mCapabilitiesChangedHistory.poll(timeoutMillis, TimeUnit.MILLISECONDS); } + public void clearLostHistory() { + mLostHistory.clear(); + } + @Override public void onAvailable(@NonNull Network network) { mAvailableHistory.offer(network); diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 70467e3f58..e1a2022b19 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -1098,6 +1098,9 @@ public class VcnManagerTest extends VcnTestBase { @NonNull VcnTestNetworkCallback cellNetworkCb, @NonNull Network vcnNetwork) throws Exception { + // Clear the history to remove other networks have been matched to the request + cellNetworkCb.clearLostHistory(); + mVcnManager.clearVcnConfig(subGrp); // Expect VCN Network to disappear after VcnConfig is cleared. @@ -1108,6 +1111,11 @@ public class VcnManagerTest extends VcnTestBase { // the VCN network MAY be immediately replaced with the underlying Cell, which only // fires an onAvailable for the new network, as opposed to an onLost() for the VCN // network. In that case, check that the VCN network has been unregistered. + // + // An alternative approach is to monitor #onAvailable as an indicator of potential + // network loss. However, since #onAvailable can mean either 1) the new network has + // higher priority, or 2) the old network is disconnected, this approach will introduce + // a lot more complexities. final Network lostVcnNetwork = cellNetworkCb.waitForLost(); if (lostVcnNetwork != null) { assertEquals(vcnNetwork, lostVcnNetwork); From 90bfefde2762035d37ce7121cfb40fa6e95f182a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 15 Aug 2023 22:12:45 +0000 Subject: [PATCH 0391/1057] Add a null pointer check for getSubscriptionsInGroup Even though #getSubscriptionsInGroup is marked @NonNull, when the Phone process crashes and this method is called from the system process, it will return null. Bug: 295339956 Test: atest CtsVcnTestCases, FrameworksVcnTests Change-Id: I9f827f9e47efef08e9905c9cc6947df84651383b --- .../src/com/android/server/VcnManagementService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index c6e9a7d5e2..7acca19f9d 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -456,7 +456,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { final List subscriptionInfos = new ArrayList<>(); Binder.withCleanCallingIdentity( () -> { - subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup)); + List subsInGroup = + subMgr.getSubscriptionsInGroup(subscriptionGroup); + if (subsInGroup == null) { + logWtf("Received null from getSubscriptionsInGroup"); + subsInGroup = Collections.emptyList(); + } + subscriptionInfos.addAll(subsInGroup); }); for (SubscriptionInfo info : subscriptionInfos) { From 8d0190fe66987c10f8d12c0a4c5d1b744625211e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Sat, 23 Sep 2023 02:20:42 +0000 Subject: [PATCH 0392/1057] DO NOT MERGE: Remove DUN capability from VCN test networks This change removes the DUN capability from test networks. The NetworkStack has started supporting DUN validation (optional in T, enabled in U), and DUN is now allowed as a capability for TEST networks. Combined, this results in tests failing on T, since DUN fails validation, but the VcnManagerTest assumes that DUN will validate. Bug: 300185717 Test: CTS tests passing Test: Manually confirmed by an affected OEM (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c9097ccb2e217df7d79923dc01d7bbf8781f5f08) Change-Id: I47a08181d26f798ed111f7f20820771c4407b154 Merged-In: Ibba855647d3b391ac94670b3672076c1fbb3fc61 --- Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index d70cc2b168..a801321118 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -158,7 +158,6 @@ public class TestNetworkWrapper implements AutoCloseable { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) - .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA) .setNetworkSpecifier(new TestNetworkSpecifier(iface)) .setSubscriptionIds(subIds); From 6922bb8e39c848d3afaa5d0e2446da003a6a22ea Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 25 Oct 2023 01:55:01 +0000 Subject: [PATCH 0393/1057] Add a flag for VCN safe mode configurability Add aconfig for VCN feature flags and the flag for VCN safe mode configurability Bug: 276358140 Test: verified flags are accessible Change-Id: I4a54445a4238c81a409604be16c90ef341eed638 --- Vcn/flags/flags.aconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Vcn/flags/flags.aconfig diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig new file mode 100644 index 0000000000..6956916af0 --- /dev/null +++ b/Vcn/flags/flags.aconfig @@ -0,0 +1,8 @@ +package: "android.net.vcn" + +flag { + name: "safe_mode_config" + namespace: "vcn" + description: "Feature flag for safe mode configurability" + bug: "276358140" +} \ No newline at end of file From 904c87775c75614e7bbc611f8784f038f98430a8 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 25 Oct 2023 01:55:01 +0000 Subject: [PATCH 0394/1057] Add a flag for VCN safe mode configurability Add aconfig for VCN feature flags and the flag for VCN safe mode configurability Bug: 276358140 Test: verified flags are accessible Change-Id: I4a54445a4238c81a409604be16c90ef341eed638 Merged-In: I4a54445a4238c81a409604be16c90ef341eed638 --- Vcn/flags/flags.aconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Vcn/flags/flags.aconfig diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig new file mode 100644 index 0000000000..6956916af0 --- /dev/null +++ b/Vcn/flags/flags.aconfig @@ -0,0 +1,8 @@ +package: "android.net.vcn" + +flag { + name: "safe_mode_config" + namespace: "vcn" + description: "Feature flag for safe mode configurability" + bug: "276358140" +} \ No newline at end of file From 0573f8de00d2d4c77b4b1faed5f39c7923811f6e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 24 Oct 2023 17:40:45 +0000 Subject: [PATCH 0395/1057] Add setter/getter to disable VCN safe mode Bug: 276358140 Test: atest FrameworksVcnTests (new tests) Test: atest CtsVcnTestCases Change-Id: I7b460cc3a3b143de212bb5a1b717fc99582f05ec --- .../net/vcn/VcnGatewayConnectionConfig.java | 46 +++++++++++++++++++ .../vcn/VcnGatewayConnectionConfigTest.java | 40 ++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index a40fb154c2..66e3c28c19 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,10 +16,12 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static com.android.internal.annotations.VisibleForTesting.Visibility; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -235,6 +237,9 @@ public final class VcnGatewayConnectionConfig { "mMinUdpPort4500NatTimeoutSeconds"; private final int mMinUdpPort4500NatTimeoutSeconds; + private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled"; + private final boolean mIsSafeModeDisabled; + private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; @NonNull private final Set mGatewayOptions; @@ -247,6 +252,7 @@ public final class VcnGatewayConnectionConfig { @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, @NonNull int minUdpPort4500NatTimeoutSeconds, + boolean isSafeModeDisabled, @NonNull Set gatewayOptions) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; @@ -255,6 +261,7 @@ public final class VcnGatewayConnectionConfig { mMaxMtu = maxMtu; mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); + mIsSafeModeDisabled = isSafeModeDisabled; mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); if (mUnderlyingNetworkTemplates.isEmpty()) { @@ -317,6 +324,7 @@ public final class VcnGatewayConnectionConfig { in.getInt( MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); + mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY); validate(); } @@ -482,6 +490,17 @@ public final class VcnGatewayConnectionConfig { return mMinUdpPort4500NatTimeoutSeconds; } + /** + * Check whether safe mode is enabled + * + * @see Builder#enableSafeMode(boolean) + * @hide + */ + @FlaggedApi(FLAG_SAFE_MODE_CONFIG) + public boolean isSafeModeEnabled() { + return !mIsSafeModeDisabled; + } + /** * Checks if the given VCN gateway option is enabled. * @@ -528,6 +547,7 @@ public final class VcnGatewayConnectionConfig { result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds); + result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled); return result; } @@ -542,6 +562,7 @@ public final class VcnGatewayConnectionConfig { Arrays.hashCode(mRetryIntervalsMs), mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, + mIsSafeModeDisabled, mGatewayOptions); } @@ -559,6 +580,7 @@ public final class VcnGatewayConnectionConfig { && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds + && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled && mGatewayOptions.equals(rhs.mGatewayOptions); } @@ -577,6 +599,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; + private boolean mIsSafeModeDisabled = false; @NonNull private final Set mGatewayOptions = new ArraySet<>(); @@ -788,6 +811,28 @@ public final class VcnGatewayConnectionConfig { return this; } + /** + * Enable/disable safe mode + * + *

    If a VCN fails to provide connectivity within a system-provided timeout, it will enter + * safe mode. In safe mode, the VCN Network will be torn down and the system will restore + * connectivity by allowing underlying cellular networks to be used as default. At the same + * time, VCN will continue to retry until it succeeds. + * + *

    When safe mode is disabled and VCN connection fails to provide connectivity, end users + * might not have connectivity, and may not have access to carrier-owned underlying + * networks. + * + * @param enabled whether safe mode should be enabled. Defaults to {@code true} + * @hide + */ + @FlaggedApi(FLAG_SAFE_MODE_CONFIG) + @NonNull + public Builder enableSafeMode(boolean enabled) { + mIsSafeModeDisabled = !enabled; + return this; + } + /** * Builds and validates the VcnGatewayConnectionConfig. * @@ -803,6 +848,7 @@ public final class VcnGatewayConnectionConfig { mRetryIntervalsMs, mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, + mIsSafeModeDisabled, mGatewayOptions); } } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index a1a39ff173..359ef83cfe 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -125,6 +125,17 @@ public class VcnGatewayConnectionConfigTest { TUNNEL_CONNECTION_PARAMS); } + private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() { + final VcnGatewayConnectionConfig.Builder builder = + new VcnGatewayConnectionConfig.Builder( + "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS); + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + return builder; + } + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions( VcnGatewayConnectionConfig.Builder builder, Set gatewayOptions, @@ -273,6 +284,7 @@ public class VcnGatewayConnectionConfigTest { assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); + assertTrue(config.isSafeModeEnabled()); assertFalse( config.hasGatewayOption( @@ -289,6 +301,13 @@ public class VcnGatewayConnectionConfigTest { } } + @Test + public void testBuilderAndGettersSafeModeDisabled() { + final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + + assertFalse(config.isSafeModeEnabled()); + } + @Test public void testPersistableBundle() { final VcnGatewayConnectionConfig config = buildTestConfig(); @@ -304,6 +323,13 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } + @Test + public void testPersistableBundleSafeModeDisabled() { + final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + + assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); + } + @Test public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() { PersistableBundle configBundle = buildTestConfig().toPersistableBundle(); @@ -411,4 +437,18 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, configEqual); assertNotEquals(config, configNotEqual); } + + @Test + public void testSafeModeEnableDisableEquality() throws Exception { + final VcnGatewayConnectionConfig config = newBuilderMinimal().build(); + final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build(); + + assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled()); + + final VcnGatewayConnectionConfig configNotEqual = + newBuilderMinimal().enableSafeMode(false).build(); + + assertEquals(config, configEqual); + assertNotEquals(config, configNotEqual); + } } From e3a5a3842f3b7a041df3c79ad26a51f93f618417 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 26 Oct 2023 01:09:28 +0000 Subject: [PATCH 0396/1057] Respect caller config to disable VCN safe mode Update VcnGatewayConnection to support disabling safe mode Bug: 276358140 Test: atest FrameworksVcnTests (new tests) Test: atest CtsVcnTestCases Change-Id: If767dbace925c7e13705db2ea6f23c890992405c --- .../com/android/server/vcn/VcnContext.java | 11 +++ .../server/vcn/VcnGatewayConnection.java | 8 +++ .../vcn/VcnGatewayConnectionConfigTest.java | 10 +++ ...cnGatewayConnectionConnectedStateTest.java | 71 +++++++++++++++++++ .../vcn/VcnGatewayConnectionTestBase.java | 13 +++- 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index d958222ea4..9213d96ad4 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -18,6 +18,8 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; +import android.net.vcn.FeatureFlags; +import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; import java.util.Objects; @@ -31,6 +33,7 @@ public class VcnContext { @NonNull private final Context mContext; @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + @NonNull private final FeatureFlags mFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -42,6 +45,9 @@ public class VcnContext { mLooper = Objects.requireNonNull(looper, "Missing looper"); mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider"); mIsInTestMode = isInTestMode; + + // Auto-generated class + mFeatureFlags = new FeatureFlagsImpl(); } @NonNull @@ -63,6 +69,11 @@ public class VcnContext { return mIsInTestMode; } + @NonNull + public FeatureFlags getFeatureFlags() { + return mFeatureFlags; + } + /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index d480ddb092..54c97dd379 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1222,6 +1222,14 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { + final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig(); + logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled); + + if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) { + logVdbg("setSafeModeAlarm: safe mode disabled"); + return; + } + logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken); // Only schedule a NEW alarm if none is already set. diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 359ef83cfe..cb3782173d 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -117,6 +117,16 @@ public class VcnGatewayConnectionConfigTest { return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES); } + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig.Builder newTestBuilderMinimal() { + final VcnGatewayConnectionConfig.Builder builder = newBuilder(); + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + return builder; + } + private static VcnGatewayConnectionConfig.Builder newBuilder() { // Append a unique identifier to the name prefix to guarantee that all created // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig). diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 302af523a4..bf73198d10 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -75,6 +75,9 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; +import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import com.android.server.vcn.util.MtuUtils; @@ -651,6 +654,74 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */); } + private void verifySetSafeModeAlarm( + boolean safeModeEnabledByCaller, + boolean safeModeConfigFlagEnabled, + boolean expectingSafeModeEnabled) + throws Exception { + final VcnGatewayConnectionConfig config = + VcnGatewayConnectionConfigTest.newTestBuilderMinimal() + .enableSafeMode(safeModeEnabledByCaller) + .build(); + final VcnGatewayConnection.Dependencies deps = + mock(VcnGatewayConnection.Dependencies.class); + setUpWakeupMessage( + mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps); + doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig(); + + final VcnGatewayConnection connection = + new VcnGatewayConnection( + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + config, + mGatewayStatusCallback, + true /* isMobileDataEnabled */, + deps); + + connection.setSafeModeAlarm(); + + final int expectedCallCnt = expectingSafeModeEnabled ? 1 : 0; + verify(deps, times(expectedCallCnt)) + .newWakeupMessage( + eq(mVcnContext), + any(), + eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM), + any()); + } + + @Test + public void testSafeModeEnabled_configFlagEnabled() throws Exception { + verifySetSafeModeAlarm( + true /* safeModeEnabledByCaller */, + true /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeEnabled_configFlagDisabled() throws Exception { + verifySetSafeModeAlarm( + true /* safeModeEnabledByCaller */, + false /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeDisabled_configFlagEnabled() throws Exception { + verifySetSafeModeAlarm( + false /* safeModeEnabledByCaller */, + true /* safeModeConfigFlagEnabled */, + false /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeDisabled_configFlagDisabled() throws Exception { + verifySetSafeModeAlarm( + false /* safeModeEnabledByCaller */, + false /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + private Consumer setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 5efbf598f9..edced87427 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -53,6 +53,7 @@ import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.vcn.FeatureFlags; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; @@ -165,6 +166,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; + @NonNull protected final FeatureFlags mFeatureFlags; @NonNull protected final VcnContext mVcnContext; @NonNull protected final VcnGatewayConnectionConfig mConfig; @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback; @@ -190,6 +192,7 @@ public class VcnGatewayConnectionTestBase { mContext = mock(Context.class); mTestLooper = new TestLooper(); mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mFeatureFlags = mock(FeatureFlags.class); mVcnContext = mock(VcnContext.class); mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class); @@ -222,6 +225,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(mUnderlyingNetworkController) .when(mDeps) @@ -241,8 +245,15 @@ public class VcnGatewayConnectionTestBase { doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime(); } + protected void setUpWakeupMessage( + @NonNull WakeupMessage msg, + @NonNull String cmdName, + VcnGatewayConnection.Dependencies deps) { + doReturn(msg).when(deps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any()); + } + private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) { - doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any()); + setUpWakeupMessage(msg, cmdName, mDeps); } @Before From 7a06189dac903f0a6a4ace4e8af7e24bc4048844 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 25 Oct 2023 02:16:42 +0000 Subject: [PATCH 0397/1057] Expose APIs to disable VCN safe mode Bug: 276358140 Test: make update-api API-Coverage-Bug: 308000143 Change-Id: Icf5df742a30ccdc5b53a2e3cc78f0efd38b2739a --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 66e3c28c19..779a8db433 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -494,7 +494,6 @@ public final class VcnGatewayConnectionConfig { * Check whether safe mode is enabled * * @see Builder#enableSafeMode(boolean) - * @hide */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) public boolean isSafeModeEnabled() { @@ -824,7 +823,6 @@ public final class VcnGatewayConnectionConfig { * networks. * * @param enabled whether safe mode should be enabled. Defaults to {@code true} - * @hide */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) @NonNull From 73348908c37aaa9621d6a5a6f5b3657ff22a44da Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 30 Oct 2023 16:59:28 -0700 Subject: [PATCH 0398/1057] Rename enableSafeMode to setSafeModeEnabled Bug: 276358140 Test: make update-api API-Coverage-Bug: 308000143 Change-Id: I3b3b9546f5a6489f203ff5b72e14ff5a29a86eaf --- .../src/android/net/vcn/VcnGatewayConnectionConfig.java | 8 ++++---- .../android/net/vcn/VcnGatewayConnectionConfigTest.java | 8 +++++--- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 779a8db433..6f11d3ae66 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -493,7 +493,7 @@ public final class VcnGatewayConnectionConfig { /** * Check whether safe mode is enabled * - * @see Builder#enableSafeMode(boolean) + * @see Builder#setSafeModeEnabled(boolean) */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) public boolean isSafeModeEnabled() { @@ -815,8 +815,8 @@ public final class VcnGatewayConnectionConfig { * *

    If a VCN fails to provide connectivity within a system-provided timeout, it will enter * safe mode. In safe mode, the VCN Network will be torn down and the system will restore - * connectivity by allowing underlying cellular networks to be used as default. At the same - * time, VCN will continue to retry until it succeeds. + * connectivity by allowing underlying cellular or WiFi networks to be used as default. At + * the same time, VCN will continue to retry until it succeeds. * *

    When safe mode is disabled and VCN connection fails to provide connectivity, end users * might not have connectivity, and may not have access to carrier-owned underlying @@ -826,7 +826,7 @@ public final class VcnGatewayConnectionConfig { */ @FlaggedApi(FLAG_SAFE_MODE_CONFIG) @NonNull - public Builder enableSafeMode(boolean enabled) { + public Builder setSafeModeEnabled(boolean enabled) { mIsSafeModeDisabled = !enabled; return this; } diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index cb3782173d..59dc689001 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -313,7 +313,8 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderAndGettersSafeModeDisabled() { - final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + final VcnGatewayConnectionConfig config = + newBuilderMinimal().setSafeModeEnabled(false).build(); assertFalse(config.isSafeModeEnabled()); } @@ -335,7 +336,8 @@ public class VcnGatewayConnectionConfigTest { @Test public void testPersistableBundleSafeModeDisabled() { - final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + final VcnGatewayConnectionConfig config = + newBuilderMinimal().setSafeModeEnabled(false).build(); assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); } @@ -456,7 +458,7 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled()); final VcnGatewayConnectionConfig configNotEqual = - newBuilderMinimal().enableSafeMode(false).build(); + newBuilderMinimal().setSafeModeEnabled(false).build(); assertEquals(config, configEqual); assertNotEquals(config, configNotEqual); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index bf73198d10..f846164263 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -661,7 +661,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection throws Exception { final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.newTestBuilderMinimal() - .enableSafeMode(safeModeEnabledByCaller) + .setSafeModeEnabled(safeModeEnabledByCaller) .build(); final VcnGatewayConnection.Dependencies deps = mock(VcnGatewayConnection.Dependencies.class); From f9532ffdbbefb5f1a9abdb2c8f291c06fcb0f7f7 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 21 Dec 2023 22:57:28 +0000 Subject: [PATCH 0399/1057] Support adjustable VCN safe mode timeout Bug: 317406085 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I8f5b6cb4e8286331626d4d39b864f0298657cab6 --- Vcn/flags/flags.aconfig | 7 ++ .../src/android/net/vcn/VcnManager.java | 15 ++++ .../com/android/server/vcn/VcnContext.java | 4 ++ .../server/vcn/VcnGatewayConnection.java | 25 ++++++- .../server/vcn/VcnGatewayConnectionTest.java | 72 +++++++++++++++++++ .../vcn/VcnGatewayConnectionTestBase.java | 1 + 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 6956916af0..67a1906d48 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -5,4 +5,11 @@ flag { namespace: "vcn" description: "Feature flag for safe mode configurability" bug: "276358140" +} + +flag { + name: "safe_mode_timeout_config" + namespace: "vcn" + description: "Feature flag for adjustable safe mode timeout" + bug: "317406085" } \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 70cf97308f..c727a60340 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -114,6 +114,20 @@ public class VcnManager { public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY = "vcn_restricted_transports"; + /** + * Key for number of seconds to wait before entering safe mode + * + *

    A VcnGatewayConnection will enter safe mode when it takes over the configured timeout to + * enter {@link ConnectedState}. + * + *

    Defaults to 30, unless overridden by carrier config + * + * @hide + */ + @NonNull + public static final String VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY = + "vcn_safe_mode_timeout_seconds_key"; + /** * Key for maximum number of parallel SAs for tunnel aggregation * @@ -135,6 +149,7 @@ public class VcnManager { VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, }; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 9213d96ad4..6ce8685400 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -74,6 +74,10 @@ public class VcnContext { return mFeatureFlags; } + public boolean isFlagSafeModeTimeoutConfigEnabled() { + return mFeatureFlags.safeModeTimeoutConfig(); + } + /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 54c97dd379..68132dcfc9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1242,9 +1242,28 @@ public class VcnGatewayConnection extends StateMachine { createScheduledAlarm( SAFEMODE_TIMEOUT_ALARM, delayedMessage, - mVcnContext.isInTestMode() - ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE) - : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + getSafeModeTimeoutMs(mVcnContext, mLastSnapshot, mSubscriptionGroup)); + } + + /** Gets the safe mode timeout */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static long getSafeModeTimeoutMs( + VcnContext vcnContext, TelephonySubscriptionSnapshot snapshot, ParcelUuid subGrp) { + final int defaultSeconds = + vcnContext.isInTestMode() + ? SAFEMODE_TIMEOUT_SECONDS_TEST_MODE + : SAFEMODE_TIMEOUT_SECONDS; + + final PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp); + int resultSeconds = defaultSeconds; + + if (vcnContext.isFlagSafeModeTimeoutConfigEnabled() && carrierConfig != null) { + resultSeconds = + carrierConfig.getInt( + VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, defaultSeconds); + } + + return TimeUnit.SECONDS.toMillis(resultSeconds); } private void cancelSafeModeAlarm() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 692c8a8f08..49665f7a33 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -27,15 +27,18 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -55,6 +58,7 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.net.vcn.VcnManager; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.os.ParcelUuid; @@ -81,6 +85,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @@ -352,4 +357,71 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { any(Executor.class), any(ConnectivityDiagnosticsCallback.class)); } + + private void verifyGetSafeModeTimeoutMs( + boolean isInTestMode, + boolean isConfigTimeoutSupported, + PersistableBundleWrapper carrierConfig, + long expectedTimeoutMs) + throws Exception { + doReturn(isInTestMode).when(mVcnContext).isInTestMode(); + doReturn(isConfigTimeoutSupported).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); + + final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); + doReturn(carrierConfig).when(snapshot).getCarrierConfigForSubGrp(TEST_SUB_GRP); + + final long result = + VcnGatewayConnection.getSafeModeTimeoutMs(mVcnContext, snapshot, TEST_SUB_GRP); + + assertEquals(expectedTimeoutMs, result); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutUnsupported() throws Exception { + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + false /* isConfigTimeoutSupported */, + null /* carrierConfig */, + TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutSupported() throws Exception { + final int carrierConfigTimeoutSeconds = 20; + final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); + doReturn(carrierConfigTimeoutSeconds) + .when(carrierConfig) + .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt()); + + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + true /* isConfigTimeoutSupported */, + carrierConfig, + TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutSupported_carrierConfigNull() + throws Exception { + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + true /* isConfigTimeoutSupported */, + null /* carrierConfig */, + TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutOverrideTestModeDefault() throws Exception { + final int carrierConfigTimeoutSeconds = 20; + final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); + doReturn(carrierConfigTimeoutSeconds) + .when(carrierConfig) + .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt()); + + verifyGetSafeModeTimeoutMs( + true /* isInTestMode */, + true /* isConfigTimeoutSupported */, + carrierConfig, + TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index edced87427..342056ad02 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -226,6 +226,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); + doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) From 5db198824b4cd7367594455c17ef4f3b9b922c0d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 8 Dec 2023 01:44:00 +0000 Subject: [PATCH 0400/1057] Refactor VCN route selection with UnderlyingNetworkEvaluator This is a preparation CL that allows followup CLs to add network metric monitors. This CL does a pure refactoring without introducing any behavior changes Specific changes include: - UnderlyingNetworkEvaluator now encapsulates the calculation of mPriorityClass - mIsSelected is moved from UnderlyingNetworkRecord to UnderlyingNetworkEvaluator - UnderlyingNetworkListener is simplified by moving the network candidate out to the UnderlyingNetworkController - NetworkPriorityClassifier now takes a "isSelected" boolean instead of the currently selected network candidate Bug: 282996138 Bug: 315858972 Test: atest FrameworksVcnTests, CtsVcnTestCases Change-Id: I8461a68f1c4260b253d84d3efed2b09c41116656 --- .../server/vcn/VcnGatewayConnection.java | 8 +- .../NetworkPriorityClassifier.java | 29 +-- .../UnderlyingNetworkController.java | 187 +++++++++------ .../UnderlyingNetworkEvaluator.java | 217 ++++++++++++++++++ .../UnderlyingNetworkRecord.java | 125 +--------- .../vcn/VcnGatewayConnectionTestBase.java | 10 +- .../NetworkEvaluationTestBase.java | 121 ++++++++++ .../NetworkPriorityClassifierTest.java | 176 ++++---------- .../UnderlyingNetworkControllerTest.java | 159 +++++++------ .../UnderlyingNetworkEvaluatorTest.java | 101 ++++++++ 10 files changed, 718 insertions(+), 415 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 54c97dd379..bcec186c36 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -915,9 +915,11 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); - logInfo( - "Selected underlying network changed: " - + (underlying == null ? null : underlying.network)); + if (!UnderlyingNetworkRecord.isSameNetwork(mUnderlying, underlying)) { + logInfo( + "Selected underlying network changed: " + + (underlying == null ? null : underlying.network)); + } // TODO(b/179091925): Move the delayed-message handling to BaseState diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 7f129ea380..d32e5cc8ef 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -47,7 +47,6 @@ import com.android.server.vcn.VcnContext; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; /** @hide */ @@ -86,7 +85,6 @@ class NetworkPriorityClassifier { *

    VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any * template as the underlying network. */ - @VisibleForTesting(visibility = Visibility.PRIVATE) static final int PRIORITY_INVALID = -1; /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */ @@ -96,7 +94,7 @@ class NetworkPriorityClassifier { List underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED @@ -118,7 +116,7 @@ class NetworkPriorityClassifier { networkRecord, subscriptionGroup, snapshot, - currentlySelected, + isSelected, carrierConfig)) { return priorityIndex; } @@ -140,12 +138,9 @@ class NetworkPriorityClassifier { UnderlyingNetworkRecord networkRecord, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; - final boolean isSelectedUnderlyingNetwork = - currentlySelected != null - && Objects.equals(currentlySelected.network, networkRecord.network); final int meteredMatch = networkPriority.getMetered(); final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED); @@ -159,7 +154,7 @@ class NetworkPriorityClassifier { if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps() || (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinEntryUpstreamBandwidthKbps() - && !isSelectedUnderlyingNetwork)) { + && !isSelected)) { return false; } @@ -167,7 +162,7 @@ class NetworkPriorityClassifier { < networkPriority.getMinExitDownstreamBandwidthKbps() || (caps.getLinkDownstreamBandwidthKbps() < networkPriority.getMinEntryDownstreamBandwidthKbps() - && !isSelectedUnderlyingNetwork)) { + && !isSelected)) { return false; } @@ -191,7 +186,7 @@ class NetworkPriorityClassifier { return checkMatchesWifiPriorityRule( (VcnWifiUnderlyingNetworkTemplate) networkPriority, networkRecord, - currentlySelected, + isSelected, carrierConfig); } @@ -214,7 +209,7 @@ class NetworkPriorityClassifier { public static boolean checkMatchesWifiPriorityRule( VcnWifiUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; @@ -223,7 +218,7 @@ class NetworkPriorityClassifier { } // TODO: Move the Network Quality check to the network metric monitor framework. - if (!isWifiRssiAcceptable(networkRecord, currentlySelected, carrierConfig)) { + if (!isWifiRssiAcceptable(networkRecord, isSelected, carrierConfig)) { return false; } @@ -237,15 +232,11 @@ class NetworkPriorityClassifier { private static boolean isWifiRssiAcceptable( UnderlyingNetworkRecord networkRecord, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; - final boolean isSelectedNetwork = - currentlySelected != null - && networkRecord.network.equals(currentlySelected.network); - if (isSelectedNetwork - && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { + if (isSelected && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { return true; } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 6afa795e96..48df44b7c4 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -48,6 +48,7 @@ import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; @@ -83,6 +84,9 @@ public class UnderlyingNetworkController { @NonNull private final TelephonyCallback mActiveDataSubIdListener = new VcnActiveDataSubscriptionIdListener(); + private final Map mUnderlyingNetworkRecords = + new ArrayMap<>(); + @NonNull private final List mCellBringupCallbacks = new ArrayList<>(); @Nullable private NetworkCallback mWifiBringupCallback; @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback; @@ -105,7 +109,8 @@ public class UnderlyingNetworkController { this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies()); } - private UnderlyingNetworkController( + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkController( @NonNull VcnContext vcnContext, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull ParcelUuid subscriptionGroup, @@ -196,6 +201,7 @@ public class UnderlyingNetworkController { NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback; List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); + mUnderlyingNetworkRecords.clear(); // Register new callbacks. Make-before-break; always register new callbacks before removal // of old callbacks @@ -395,6 +401,18 @@ public class UnderlyingNetworkController { // Update carrier config mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup); + // Make sure all evaluators use the same updated TelephonySubscriptionSnapshot and carrier + // config to calculate their cached priority classes. For simplicity, the + // UnderlyingNetworkController does not listen for changes in VCN-related carrier config + // keys, and changes are applied at restart of the VcnGatewayConnection + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.reevaluate( + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + } + // Only trigger re-registration if subIds in this group have changed if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) @@ -418,32 +436,62 @@ public class UnderlyingNetworkController { .unregisterTelephonyCallback(mActiveDataSubIdListener); } + private TreeSet getSortedUnderlyingNetworks() { + TreeSet sorted = + new TreeSet<>(UnderlyingNetworkEvaluator.getComparator()); + + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + if (evaluator.getPriorityClass() != NetworkPriorityClassifier.PRIORITY_INVALID) { + sorted.add(evaluator); + } + } + + return sorted; + } + private void reevaluateNetworks() { if (mIsQuitting || mRouteSelectionCallback == null) { return; // UnderlyingNetworkController has quit. } - TreeSet sorted = - mRouteSelectionCallback.getSortedUnderlyingNetworks(); - UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); + TreeSet sorted = getSortedUnderlyingNetworks(); + + UnderlyingNetworkEvaluator candidateEvaluator = sorted.isEmpty() ? null : sorted.first(); + UnderlyingNetworkRecord candidate = + candidateEvaluator == null ? null : candidateEvaluator.getNetworkRecord(); if (Objects.equals(mCurrentRecord, candidate)) { return; } String allNetworkPriorities = ""; - for (UnderlyingNetworkRecord record : sorted) { + for (UnderlyingNetworkEvaluator recordEvaluator : sorted) { if (!allNetworkPriorities.isEmpty()) { allNetworkPriorities += ", "; } - allNetworkPriorities += record.network + ": " + record.priorityClass; + allNetworkPriorities += + recordEvaluator.getNetwork() + ": " + recordEvaluator.getPriorityClass(); } - logInfo( - "Selected network changed to " - + (candidate == null ? null : candidate.network) - + ", selected from list: " - + allNetworkPriorities); + + if (!UnderlyingNetworkRecord.isSameNetwork(mCurrentRecord, candidate)) { + logInfo( + "Selected network changed to " + + (candidate == null ? null : candidate.network) + + ", selected from list: " + + allNetworkPriorities); + } + mCurrentRecord = candidate; mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); + + // Need to update all evaluators to ensure the previously selected one is unselected + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.setIsSelected( + candidateEvaluator == evaluator, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + } } /** @@ -463,46 +511,26 @@ public class UnderlyingNetworkController { */ @VisibleForTesting class UnderlyingNetworkListener extends NetworkCallback { - private final Map - mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); - UnderlyingNetworkListener() { super(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO); } - private TreeSet getSortedUnderlyingNetworks() { - TreeSet sorted = - new TreeSet<>(UnderlyingNetworkRecord.getComparator()); - - for (UnderlyingNetworkRecord.Builder builder : - mUnderlyingNetworkRecordBuilders.values()) { - if (builder.isValid()) { - final UnderlyingNetworkRecord record = - builder.build( - mVcnContext, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), - mSubscriptionGroup, - mLastSnapshot, - mCurrentRecord, - mCarrierConfig); - if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) { - sorted.add(record); - } - } - } - - return sorted; - } - @Override public void onAvailable(@NonNull Network network) { - mUnderlyingNetworkRecordBuilders.put( - network, new UnderlyingNetworkRecord.Builder(network)); + mUnderlyingNetworkRecords.put( + network, + mDeps.newUnderlyingNetworkEvaluator( + mVcnContext, + network, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig)); } @Override public void onLost(@NonNull Network network) { - mUnderlyingNetworkRecordBuilders.remove(network); + mUnderlyingNetworkRecords.remove(network); reevaluateNetworks(); } @@ -510,15 +538,20 @@ public class UnderlyingNetworkController { @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got capabilities change for unknown key: " + network); return; } - builder.setNetworkCapabilities(networkCapabilities); - if (builder.isValid()) { + evaluator.setNetworkCapabilities( + networkCapabilities, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } @@ -526,30 +559,40 @@ public class UnderlyingNetworkController { @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got link properties change for unknown key: " + network); return; } - builder.setLinkProperties(linkProperties); - if (builder.isValid()) { + evaluator.setLinkProperties( + linkProperties, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } @Override public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got blocked status change for unknown key: " + network); return; } - builder.setIsBlocked(isBlocked); - if (builder.isValid()) { + evaluator.setIsBlocked( + isBlocked, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } @@ -614,16 +657,8 @@ public class UnderlyingNetworkController { pw.println("Underlying networks:"); pw.increaseIndent(); if (mRouteSelectionCallback != null) { - for (UnderlyingNetworkRecord record : - mRouteSelectionCallback.getSortedUnderlyingNetworks()) { - record.dump( - mVcnContext, - pw, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), - mSubscriptionGroup, - mLastSnapshot, - mCurrentRecord, - mCarrierConfig); + for (UnderlyingNetworkEvaluator recordEvaluator : getSortedUnderlyingNetworks()) { + recordEvaluator.dump(pw); } } pw.decreaseIndent(); @@ -653,5 +688,23 @@ public class UnderlyingNetworkController { @Nullable UnderlyingNetworkRecord underlyingNetworkRecord); } - private static class Dependencies {} + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Construct a new UnderlyingNetworkEvaluator */ + public UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + return new UnderlyingNetworkEvaluator( + vcnContext, + network, + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + carrierConfig); + } + } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java new file mode 100644 index 0000000000..c124a1976a --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.os.ParcelUuid; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +/** + * UnderlyingNetworkEvaluator evaluates the quality and priority class of a network candidate for + * route selection. + * + * @hide + */ +public class UnderlyingNetworkEvaluator { + private static final String TAG = UnderlyingNetworkEvaluator.class.getSimpleName(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final UnderlyingNetworkRecord.Builder mNetworkRecordBuilder; + + private boolean mIsSelected; + private int mPriorityClass = NetworkPriorityClassifier.PRIORITY_INVALID; + + public UnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + + Objects.requireNonNull(underlyingNetworkTemplates, "Missing underlyingNetworkTemplates"); + Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + Objects.requireNonNull(lastSnapshot, "Missing lastSnapshot"); + + mNetworkRecordBuilder = + new UnderlyingNetworkRecord.Builder( + Objects.requireNonNull(network, "Missing network")); + mIsSelected = false; + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + private void updatePriorityClass( + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + if (mNetworkRecordBuilder.isValid()) { + mPriorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + mNetworkRecordBuilder.build(), + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + mIsSelected, + carrierConfig); + } else { + mPriorityClass = NetworkPriorityClassifier.PRIORITY_INVALID; + } + } + + public static Comparator getComparator() { + return (left, right) -> { + final int leftIndex = left.mPriorityClass; + final int rightIndex = right.mPriorityClass; + + // In the case of networks in the same priority class, prioritize based on other + // criteria (eg. actively selected network, link metrics, etc) + if (leftIndex == rightIndex) { + // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord + // fall into the same priority class. + if (left.mIsSelected) { + return -1; + } + if (right.mIsSelected) { + return 1; + } + } + return Integer.compare(leftIndex, rightIndex); + }; + } + + /** Set the NetworkCapabilities */ + public void setNetworkCapabilities( + @NonNull NetworkCapabilities nc, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setNetworkCapabilities(nc); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set the LinkProperties */ + public void setLinkProperties( + @NonNull LinkProperties lp, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setLinkProperties(lp); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set whether the network is blocked */ + public void setIsBlocked( + boolean isBlocked, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setIsBlocked(isBlocked); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set whether the network is selected as VCN's underlying network */ + public void setIsSelected( + boolean isSelected, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mIsSelected = isSelected; + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** + * Update the last TelephonySubscriptionSnapshot and carrier config to reevaluate the network + */ + public void reevaluate( + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Return whether this network evaluator is valid */ + public boolean isValid() { + return mNetworkRecordBuilder.isValid(); + } + + /** Return the network */ + public Network getNetwork() { + return mNetworkRecordBuilder.getNetwork(); + } + + /** Return the network record */ + public UnderlyingNetworkRecord getNetworkRecord() { + return mNetworkRecordBuilder.build(); + } + + /** Return the priority class for network selection */ + public int getPriorityClass() { + return mPriorityClass; + } + + /** Dump the information of this instance */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkEvaluator:"); + pw.increaseIndent(); + + if (mNetworkRecordBuilder.isValid()) { + getNetworkRecord().dump(pw); + } else { + pw.println( + "UnderlyingNetworkRecord incomplete: mNetwork: " + + mNetworkRecordBuilder.getNetwork()); + } + + pw.println("mIsSelected: " + mIsSelected); + pw.println("mPriorityClass: " + mPriorityClass); + + pw.decreaseIndent(); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index aea9f4d2db..7ab8e55272 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -16,24 +16,17 @@ package com.android.server.vcn.routeselection; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.vcn.VcnUnderlyingNetworkTemplate; -import android.os.ParcelUuid; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.VcnContext; -import java.util.Comparator; -import java.util.List; import java.util.Objects; /** @@ -46,54 +39,17 @@ public class UnderlyingNetworkRecord { @NonNull public final NetworkCapabilities networkCapabilities; @NonNull public final LinkProperties linkProperties; public final boolean isBlocked; - public final boolean isSelected; - public final int priorityClass; @VisibleForTesting(visibility = Visibility.PRIVATE) public UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, - boolean isBlocked, - VcnContext vcnContext, - List underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + boolean isBlocked) { this.network = network; this.networkCapabilities = networkCapabilities; this.linkProperties = linkProperties; this.isBlocked = isBlocked; - - this.isSelected = isSelected(this.network, currentlySelected); - - priorityClass = - NetworkPriorityClassifier.calculatePriorityClass( - vcnContext, - this, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); - } - - @VisibleForTesting(visibility = Visibility.PRIVATE) - public UnderlyingNetworkRecord( - @NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, - boolean isBlocked, - boolean isSelected, - int priorityClass) { - this.network = network; - this.networkCapabilities = networkCapabilities; - this.linkProperties = linkProperties; - this.isBlocked = isBlocked; - this.isSelected = isSelected; - - this.priorityClass = priorityClass; } @Override @@ -113,64 +69,20 @@ public class UnderlyingNetworkRecord { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } - /** Returns if two records are equal including their priority classes. */ - public static boolean isEqualIncludingPriorities( - UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) { - if (left != null && right != null) { - return left.equals(right) - && left.isSelected == right.isSelected - && left.priorityClass == right.priorityClass; - } - - return left == right; - } - - static Comparator getComparator() { - return (left, right) -> { - final int leftIndex = left.priorityClass; - final int rightIndex = right.priorityClass; - - // In the case of networks in the same priority class, prioritize based on other - // criteria (eg. actively selected network, link metrics, etc) - if (leftIndex == rightIndex) { - // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord - // fall into the same priority class. - if (left.isSelected) { - return -1; - } - if (right.isSelected) { - return 1; - } - } - return Integer.compare(leftIndex, rightIndex); - }; - } - - private static boolean isSelected( - Network networkToCheck, UnderlyingNetworkRecord currentlySelected) { - if (currentlySelected == null) { - return false; - } - if (currentlySelected.network.equals(networkToCheck)) { - return true; - } - return false; + /** Return whether two records represent the same network */ + public static boolean isSameNetwork( + @Nullable UnderlyingNetworkRecord leftRecord, + @Nullable UnderlyingNetworkRecord rightRecord) { + final Network left = leftRecord == null ? null : leftRecord.network; + final Network right = rightRecord == null ? null : rightRecord.network; + return Objects.equals(left, right); } /** Dumps the state of this record for logging and debugging purposes. */ - void dump( - VcnContext vcnContext, - IndentingPrintWriter pw, - List underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); - pw.println("priorityClass: " + priorityClass); - pw.println("isSelected: " + isSelected); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); @@ -218,29 +130,14 @@ public class UnderlyingNetworkRecord { return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; } - UnderlyingNetworkRecord build( - VcnContext vcnContext, - List underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + UnderlyingNetworkRecord build() { if (!isValid()) { throw new IllegalArgumentException( "Called build before UnderlyingNetworkRecord was valid"); } return new UnderlyingNetworkRecord( - mNetwork, - mNetworkCapabilities, - mLinkProperties, - mIsBlocked, - vcnContext, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); } } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index edced87427..8374fd9445 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -67,6 +67,8 @@ import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock; import com.android.server.vcn.routeselection.UnderlyingNetworkController; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; @@ -118,13 +120,7 @@ public class VcnGatewayConnectionTestBase { NetworkCapabilities networkCapabilities, LinkProperties linkProperties, boolean isBlocked) { - return new UnderlyingNetworkRecord( - network, - networkCapabilities, - linkProperties, - isBlocked, - false /* isSelected */, - 0 /* priorityClass */); + return new UnderlyingNetworkRecord(network, networkCapabilities, linkProperties, isBlocked); } protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4"; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java new file mode 100644 index 0000000000..bf84bbeeed --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static com.android.server.vcn.VcnTestUtils.setupSystemService; +import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.os.ParcelUuid; +import android.os.test.TestLooper; +import android.telephony.TelephonyManager; + +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; + +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Set; +import java.util.UUID; + +public abstract class NetworkEvaluationTestBase { + protected static final String SSID = "TestWifi"; + protected static final String SSID_OTHER = "TestWifiOther"; + protected static final String PLMN_ID = "123456"; + protected static final String PLMN_ID_OTHER = "234567"; + + protected static final int SUB_ID = 1; + protected static final int WIFI_RSSI = -60; + protected static final int WIFI_RSSI_HIGH = -50; + protected static final int WIFI_RSSI_LOW = -80; + protected static final int CARRIER_ID = 1; + protected static final int CARRIER_ID_OTHER = 2; + + protected static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024; + protected static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048; + + protected static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100; + protected static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200; + + protected static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + + protected static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .setSignalStrength(WIFI_RSSI) + .setSsid(SSID) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) + .build(); + + protected static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); + protected static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setSubscriptionIds(Set.of(SUB_ID)) + .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) + .build(); + + protected static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); + + @Mock protected Network mNetwork; + @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; + @Mock protected TelephonyManager mTelephonyManager; + + protected TestLooper mTestLooper; + protected VcnContext mVcnContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + final Context mockContext = mock(Context.class); + mTestLooper = new TestLooper(); + mVcnContext = + spy( + new VcnContext( + mockContext, + mTestLooper.getLooper(), + mock(VcnNetworkProvider.class), + false /* isInTestMode */)); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + + setupSystemService( + mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); + when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); + when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 2266041085..dbf2f514fe 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -24,152 +24,48 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTR import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS; import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS; -import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; -import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import android.content.Context; -import android.net.LinkProperties; -import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; -import android.os.ParcelUuid; import android.os.PersistableBundle; -import android.os.test.TestLooper; -import android.telephony.TelephonyManager; import android.util.ArraySet; -import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.VcnContext; -import com.android.server.vcn.VcnNetworkProvider; - import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.UUID; -public class NetworkPriorityClassifierTest { - private static final String SSID = "TestWifi"; - private static final String SSID_OTHER = "TestWifiOther"; - private static final String PLMN_ID = "123456"; - private static final String PLMN_ID_OTHER = "234567"; - - private static final int SUB_ID = 1; - private static final int WIFI_RSSI = -60; - private static final int WIFI_RSSI_HIGH = -50; - private static final int WIFI_RSSI_LOW = -80; - private static final int CARRIER_ID = 1; - private static final int CARRIER_ID_OTHER = 2; - - private static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024; - private static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048; - - private static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100; - private static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200; - - private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); - - private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .setSignalStrength(WIFI_RSSI) - .setSsid(SSID) - .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) - .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) - .build(); - - private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = - new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); - private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = - new NetworkCapabilities.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setSubscriptionIds(Set.of(SUB_ID)) - .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) - .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) - .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) - .build(); - - private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); - - @Mock private Network mNetwork; - @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; - @Mock private TelephonyManager mTelephonyManager; - - private TestLooper mTestLooper; - private VcnContext mVcnContext; +public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase { private UnderlyingNetworkRecord mWifiNetworkRecord; private UnderlyingNetworkRecord mCellNetworkRecord; @Before public void setUp() { - MockitoAnnotations.initMocks(this); + super.setUp(); - final Context mockContext = mock(Context.class); - mTestLooper = new TestLooper(); - mVcnContext = - spy( - new VcnContext( - mockContext, - mTestLooper.getLooper(), - mock(VcnNetworkProvider.class), - false /* isInTestMode */)); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - - setupSystemService( - mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); - when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); - when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); - when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); - - mWifiNetworkRecord = - getTestNetworkRecord( - WIFI_NETWORK_CAPABILITIES, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); - mCellNetworkRecord = - getTestNetworkRecord( - CELL_NETWORK_CAPABILITIES, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); + mWifiNetworkRecord = getTestNetworkRecord(WIFI_NETWORK_CAPABILITIES); + mCellNetworkRecord = getTestNetworkRecord(CELL_NETWORK_CAPABILITIES); } - private UnderlyingNetworkRecord getTestNetworkRecord( - NetworkCapabilities nc, List underlyingNetworkTemplates) { - return new UnderlyingNetworkRecord( - mNetwork, - nc, - LINK_PROPERTIES, - false /* isBlocked */, - mVcnContext, - underlyingNetworkTemplates, - SUB_GROUP, - mSubscriptionSnapshot, - null /* currentlySelected */, - null /* carrierConfig */); + private UnderlyingNetworkRecord getTestNetworkRecord(NetworkCapabilities nc) { + return new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */); } @Test @@ -186,14 +82,14 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - null /* currentlySelecetd */, + false /* isSelected */, null /* carrierConfig */)); } private void verifyMatchesPriorityRuleForUpstreamBandwidth( int entryUpstreamBandwidth, int exitUpstreamBandwidth, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, boolean expectMatch) { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() @@ -208,14 +104,14 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - currentlySelected, + isSelected, null /* carrierConfig */)); } private void verifyMatchesPriorityRuleForDownstreamBandwidth( int entryDownstreamBandwidth, int exitDownstreamBandwidth, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, boolean expectMatch) { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() @@ -231,7 +127,7 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - currentlySelected, + isSelected, null /* carrierConfig */)); } @@ -240,7 +136,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, - null /* currentlySelected */, + false /* isSelected */, true); } @@ -249,7 +145,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( LINK_UPSTREAM_BANDWIDTH_KBPS + 1, LINK_UPSTREAM_BANDWIDTH_KBPS + 1, - null /* currentlySelected */, + false /* isSelected */, false); } @@ -258,7 +154,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, - null /* currentlySelected */, + false /* isSelected */, true); } @@ -267,7 +163,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, - null /* currentlySelected */, + false /* isSelected */, false); } @@ -276,7 +172,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, - mWifiNetworkRecord, + true /* isSelected */, true); } @@ -285,7 +181,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( LINK_UPSTREAM_BANDWIDTH_KBPS + 1, LINK_UPSTREAM_BANDWIDTH_KBPS + 1, - mWifiNetworkRecord, + true /* isSelected */, false); } @@ -294,7 +190,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, - mWifiNetworkRecord, + true /* isSelected */, true); } @@ -303,7 +199,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, - mWifiNetworkRecord, + true /* isSelected */, false); } @@ -318,14 +214,12 @@ public class NetworkPriorityClassifierTest { TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .build(); - final UnderlyingNetworkRecord selectedNetworkRecord = - isSelectedNetwork ? mWifiNetworkRecord : null; assertEquals( expectMatch, checkMatchesWifiPriorityRule( wifiNetworkPriority, mWifiNetworkRecord, - selectedNetworkRecord, + isSelectedNetwork, carrierConfig == null ? null : new PersistableBundleWrapper(carrierConfig))); @@ -381,7 +275,7 @@ public class NetworkPriorityClassifierTest { checkMatchesWifiPriorityRule( wifiNetworkPriority, mWifiNetworkRecord, - null /* currentlySelecetd */, + false /* isSelected */, null /* carrierConfig */)); } @@ -516,7 +410,7 @@ public class NetworkPriorityClassifierTest { mCellNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - null /* currentlySelected */, + false /* isSelected */, null /* carrierConfig */)); } @@ -543,7 +437,16 @@ public class NetworkPriorityClassifierTest { @Test public void testCalculatePriorityClass() throws Exception { - assertEquals(2, mCellNetworkRecord.priorityClass); + final int priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + mCellNetworkRecord, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + false /* isSelected */, + null /* carrierConfig */); + assertEquals(2, priorityClass); } private void checkCalculatePriorityClassFailToMatchAny( @@ -561,10 +464,19 @@ public class NetworkPriorityClassifierTest { ncBuilder.addCapability(NET_CAPABILITY_INTERNET); } - final UnderlyingNetworkRecord nonDunNetworkRecord = - getTestNetworkRecord(ncBuilder.build(), templatesRequireDun); + final UnderlyingNetworkRecord nonDunNetworkRecord = getTestNetworkRecord(ncBuilder.build()); - assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass); + final int priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + nonDunNetworkRecord, + templatesRequireDun, + SUB_GROUP, + mSubscriptionSnapshot, + false /* isSelected */, + null /* carrierConfig */); + + assertEquals(expectedPriorityClass, priorityClass); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 2941fdea20..992f102757 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -29,13 +29,12 @@ import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WI import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -67,6 +66,7 @@ import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.Dependencies; import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; @@ -77,6 +77,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.util.ArrayList; import java.util.Arrays; @@ -154,10 +155,13 @@ public class UnderlyingNetworkControllerTest { @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb; @Mock private Network mNetwork; + @Spy private Dependencies mDependencies = new Dependencies(); + @Captor private ArgumentCaptor mUnderlyingNetworkListenerCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; + private UnderlyingNetworkEvaluator mNetworkEvaluator; private UnderlyingNetworkController mUnderlyingNetworkController; @Before @@ -189,13 +193,28 @@ public class UnderlyingNetworkControllerTest { when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); + mNetworkEvaluator = + spy( + new UnderlyingNetworkEvaluator( + mVcnContext, + mNetwork, + VcnGatewayConnectionConfigTest.buildTestConfig() + .getVcnUnderlyingNetworkPriorities(), + SUB_GROUP, + mSubscriptionSnapshot, + null)); + doReturn(mNetworkEvaluator) + .when(mDependencies) + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any()); + mUnderlyingNetworkController = new UnderlyingNetworkController( mVcnContext, VcnGatewayConnectionConfigTest.buildTestConfig(), SUB_GROUP, mSubscriptionSnapshot, - mNetworkControllerCb); + mNetworkControllerCb, + mDependencies); } private void resetVcnContext() { @@ -489,13 +508,7 @@ public class UnderlyingNetworkControllerTest { NetworkCapabilities networkCapabilities, LinkProperties linkProperties, boolean isBlocked) { - return new UnderlyingNetworkRecord( - network, - networkCapabilities, - linkProperties, - isBlocked, - false /* isSelected */, - 0 /* priorityClass */); + return new UnderlyingNetworkRecord(network, networkCapabilities, linkProperties, isBlocked); } @Test @@ -514,25 +527,13 @@ public class UnderlyingNetworkControllerTest { false /* isBlocked */); UnderlyingNetworkRecord recordC = new UnderlyingNetworkRecord( - mNetwork, - INITIAL_NETWORK_CAPABILITIES, - INITIAL_LINK_PROPERTIES, - false /* isBlocked */, - true /* isSelected */, - -1 /* priorityClass */); - UnderlyingNetworkRecord recordD = - getTestNetworkRecord( mNetwork, UPDATED_NETWORK_CAPABILITIES, UPDATED_LINK_PROPERTIES, false /* isBlocked */); assertEquals(recordA, recordB); - assertEquals(recordA, recordC); - assertNotEquals(recordA, recordD); - - assertTrue(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordB)); - assertFalse(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordC)); + assertNotEquals(recordA, recordC); } @Test @@ -540,6 +541,19 @@ public class UnderlyingNetworkControllerTest { verifyRegistrationOnAvailableAndGetCallback(); } + @Test + public void testUpdateSubscriptionSnapshotAndCarrierConfig() { + verifyRegistrationOnAvailableAndGetCallback(); + + TelephonySubscriptionSnapshot subscriptionUpdate = + mock(TelephonySubscriptionSnapshot.class); + when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS); + + mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate); + + verify(mNetworkEvaluator).reevaluate(any(), any(), any(), any()); + } + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } @@ -583,6 +597,7 @@ public class UnderlyingNetworkControllerTest { INITIAL_LINK_PROPERTIES, false /* isBlocked */); verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); + verify(mNetworkEvaluator).setIsSelected(eq(true), any(), any(), any(), any()); return cb; } @@ -713,7 +728,8 @@ public class UnderlyingNetworkControllerTest { VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates), SUB_GROUP, mSubscriptionSnapshot, - mNetworkControllerCb); + mNetworkControllerCb, + mDependencies); verify(cm) .registerNetworkCallback( @@ -724,30 +740,43 @@ public class UnderlyingNetworkControllerTest { return mUnderlyingNetworkListenerCaptor.getValue(); } - private UnderlyingNetworkRecord bringupNetworkAndGetRecord( + private UnderlyingNetworkEvaluator bringupNetworkAndGetEvaluator( UnderlyingNetworkListener cb, NetworkCapabilities requestNetworkCaps, - List underlyingNetworkTemplates, - UnderlyingNetworkRecord currentlySelected) { + List underlyingNetworkTemplates) { final Network network = mock(Network.class); final NetworkCapabilities responseNetworkCaps = buildResponseNwCaps(requestNetworkCaps, INITIAL_SUB_IDS); + final UnderlyingNetworkEvaluator evaluator = + spy( + new UnderlyingNetworkEvaluator( + mVcnContext, + network, + underlyingNetworkTemplates, + SUB_GROUP, + mSubscriptionSnapshot, + null)); + doReturn(evaluator) + .when(mDependencies) + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any()); cb.onAvailable(network); cb.onCapabilitiesChanged(network, responseNetworkCaps); cb.onLinkPropertiesChanged(network, INITIAL_LINK_PROPERTIES); cb.onBlockedStatusChanged(network, false /* isFalse */); - return new UnderlyingNetworkRecord( - network, - responseNetworkCaps, - INITIAL_LINK_PROPERTIES, - false /* isBlocked */, - mVcnContext, - underlyingNetworkTemplates, - SUB_GROUP, - mSubscriptionSnapshot, - currentlySelected, - null /* carrierConfig */); + + return evaluator; + } + + private void verifySelectNetwork(UnderlyingNetworkEvaluator expectedEvaluator) { + verifyOnSelectedUnderlyingNetworkChanged(expectedEvaluator.getNetworkRecord()); + verify(expectedEvaluator).setIsSelected(eq(true), any(), any(), any(), any()); + } + + private void verifyNeverSelectNetwork(UnderlyingNetworkEvaluator expectedEvaluator) { + verify(mNetworkControllerCb, never()) + .onSelectedUnderlyingNetworkChanged(eq(expectedEvaluator.getNetworkRecord())); + verify(expectedEvaluator, never()).setIsSelected(eq(true), any(), any(), any(), any()); } @Test @@ -759,19 +788,15 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up CBS network - final UnderlyingNetworkRecord cbsNetworkRecord = - bringupNetworkAndGetRecord( - cb, - CBS_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + final UnderlyingNetworkEvaluator cbsNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(cbsNetworkEvaluator); // Bring up DUN network - final UnderlyingNetworkRecord dunNetworkRecord = - bringupNetworkAndGetRecord( - cb, DUN_NETWORK_CAPABILITIES, networkTemplates, cbsNetworkRecord); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + final UnderlyingNetworkEvaluator dunNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, DUN_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(dunNetworkEvaluator); + verify(cbsNetworkEvaluator).setIsSelected(eq(false), any(), any(), any(), any()); } @Test @@ -783,20 +808,14 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up DUN network - final UnderlyingNetworkRecord dunNetworkRecord = - bringupNetworkAndGetRecord( - cb, - DUN_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + final UnderlyingNetworkEvaluator dunNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, DUN_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(dunNetworkEvaluator); // Bring up CBS network - final UnderlyingNetworkRecord cbsNetworkRecord = - bringupNetworkAndGetRecord( - cb, CBS_NETWORK_CAPABILITIES, networkTemplates, dunNetworkRecord); - verify(mNetworkControllerCb, never()) - .onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + final UnderlyingNetworkEvaluator cbsNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifyNeverSelectNetwork(cbsNetworkEvaluator); } @Test @@ -808,13 +827,9 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up an Internet network without DUN capability - final UnderlyingNetworkRecord networkRecord = - bringupNetworkAndGetRecord( - cb, - INITIAL_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(networkRecord)); + final UnderlyingNetworkEvaluator evaluator = + bringupNetworkAndGetEvaluator(cb, INITIAL_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(evaluator); } @Test @@ -825,10 +840,8 @@ public class UnderlyingNetworkControllerTest { new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build()); UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); - bringupNetworkAndGetRecord( - cb, CBS_NETWORK_CAPABILITIES, networkTemplates, null /* currentlySelected */); - - verify(mNetworkControllerCb, never()) - .onSelectedUnderlyingNetworkChanged(any(UnderlyingNetworkRecord.class)); + final UnderlyingNetworkEvaluator evaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifyNeverSelectNetwork(evaluator); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java new file mode 100644 index 0000000000..a4567ddc20 --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +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.vcn.VcnGatewayConnectionConfig; +import android.os.PersistableBundle; + +import org.junit.Before; +import org.junit.Test; + +public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { + private PersistableBundleWrapper mCarrierConfig; + + @Before + public void setUp() { + super.setUp(); + mCarrierConfig = new PersistableBundleWrapper(new PersistableBundle()); + } + + private UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator() { + return new UnderlyingNetworkEvaluator( + mVcnContext, + mNetwork, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + } + + @Test + public void testInitializedEvaluator() throws Exception { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + + assertFalse(evaluator.isValid()); + assertEquals(mNetwork, evaluator.getNetwork()); + assertEquals(PRIORITY_INVALID, evaluator.getPriorityClass()); + + try { + evaluator.getNetworkRecord(); + fail("Expected to fail because evaluator is not valid"); + } catch (Exception expected) { + } + } + + @Test + public void testValidEvaluator() { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + evaluator.setNetworkCapabilities( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setLinkProperties( + LINK_PROPERTIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setIsBlocked( + false /* isBlocked */, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + final UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + CELL_NETWORK_CAPABILITIES, + LINK_PROPERTIES, + false /* isBlocked */); + + assertTrue(evaluator.isValid()); + assertEquals(mNetwork, evaluator.getNetwork()); + assertEquals(2, evaluator.getPriorityClass()); + assertEquals(expectedRecord, evaluator.getNetworkRecord()); + } +} From 421db12030bed874725c08059eac247ca1b29d61 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 8 Dec 2023 18:48:01 +0000 Subject: [PATCH 0401/1057] Support IPsec packet loss detector This CL creates an abstract class NetworkMetricMonitor and a subclass IpSecPacketLossDetector. IpSecPacketLossDetector is responsible for continuously monitoring IPsec packet loss and reporting to the caller when the data loss rate surpass a threshold. This detector allows the VCN to switch from the underlying network that has bad quality. This CL also defines new carrier configs that specify the data loss threshold and detecting frequency Bug: 282996138 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I5f4b8e1821bdbb37f0a6de6e1584f8e3c87273f3 --- Vcn/flags/flags.aconfig | 7 + .../src/android/net/vcn/VcnManager.java | 20 + .../com/android/server/vcn/VcnContext.java | 10 + .../IpSecPacketLossDetector.java | 387 ++++++++++++++++ .../routeselection/NetworkMetricMonitor.java | 269 +++++++++++ .../IpSecPacketLossDetectorTest.java | 419 ++++++++++++++++++ .../NetworkEvaluationTestBase.java | 31 +- .../NetworkPriorityClassifierTest.java | 2 +- .../UnderlyingNetworkEvaluatorTest.java | 2 +- 9 files changed, 1141 insertions(+), 6 deletions(-) create mode 100644 Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java create mode 100644 Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java create mode 100644 Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 67a1906d48..7afd72195f 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -12,4 +12,11 @@ flag { namespace: "vcn" description: "Feature flag for adjustable safe mode timeout" bug: "317406085" +} + +flag{ + name: "network_metric_monitor" + namespace: "vcn" + description: "Feature flag for enabling network metric monitor" + bug: "282996138" } \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index c727a60340..561db9c8a8 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -102,6 +102,24 @@ public class VcnManager { public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY = "vcn_network_selection_wifi_exit_rssi_threshold"; + /** + * Key for the interval to poll IpSecTransformState for packet loss monitoring + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY = + "vcn_network_selection_poll_ipsec_state_interval_seconds"; + + /** + * Key for the threshold of IPSec packet loss rate + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY = + "vcn_network_selection_ipsec_packet_loss_percent_threshold"; + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz /** @@ -148,6 +166,8 @@ public class VcnManager { new String[] { VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, + VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 6ce8685400..ed04e5fde0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -34,6 +34,7 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; + @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -48,6 +49,7 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); + mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl(); } @NonNull @@ -69,6 +71,14 @@ public class VcnContext { return mIsInTestMode; } + public boolean isFlagNetworkMetricMonitorEnabled() { + return mFeatureFlags.networkMetricMonitor(); + } + + public boolean isFlagIpSecTransformStateEnabled() { + return mCoreNetFeatureFlags.ipsecTransformState(); + } + @NonNull public FeatureFlags getFeatureFlags() { return mFeatureFlags; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java new file mode 100644 index 0000000000..5f4852f777 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.IpSecTransformState; +import android.net.Network; +import android.net.vcn.VcnManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.OutcomeReceiver; +import android.os.PowerManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.VcnContext; + +import java.util.BitSet; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * IpSecPacketLossDetector is responsible for continuously monitoring IPsec packet loss + * + *

    When the packet loss rate surpass the threshold, IpSecPacketLossDetector will report it to the + * caller + * + *

    IpSecPacketLossDetector will start monitoring when the network being monitored is selected AND + * an inbound IpSecTransform has been applied to this network. + * + *

    This class is flag gated by "network_metric_monitor" and "ipsec_tramsform_state" + */ +public class IpSecPacketLossDetector extends NetworkMetricMonitor { + private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PACKET_LOSS_UNAVALAIBLE = -1; + + // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality + // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and + // Security"). For audio and video streaming, above 10-12% packet loss is unacceptable (as per + // "ICTP-SDU: About PingER"). Thus choose 12% as a conservative default threshold to declare a + // validation failure. + private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT = 12; + + private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20; + + private long mPollIpSecStateIntervalMs; + private final int mPacketLossRatePercentThreshold; + + @NonNull private final Handler mHandler; + @NonNull private final PowerManager mPowerManager; + @NonNull private final Object mCancellationToken = new Object(); + @NonNull private final PacketLossCalculator mPacketLossCalculator; + + @Nullable private IpSecTransformWrapper mInboundTransform; + @Nullable private IpSecTransformState mLastIpSecTransformState; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public IpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback, + @NonNull Dependencies deps) + throws IllegalAccessException { + super(vcnContext, network, carrierConfig, callback); + + Objects.requireNonNull(deps, "Missing deps"); + + if (!vcnContext.isFlagIpSecTransformStateEnabled()) { + // Caller error + logWtf("ipsecTransformState flag disabled"); + throw new IllegalAccessException("ipsecTransformState flag disabled"); + } + + mHandler = new Handler(getVcnContext().getLooper()); + + mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class); + + mPacketLossCalculator = deps.getPacketLossCalculator(); + + mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + + // Register for system broadcasts to monitor idle mode change + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + getVcnContext() + .getContext() + .registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals( + intent.getAction()) + && mPowerManager.isDeviceIdleMode()) { + mLastIpSecTransformState = null; + } + } + }, + intentFilter, + null /* broadcastPermission not required */, + mHandler); + } + + public IpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + this(vcnContext, network, carrierConfig, callback, new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + public PacketLossCalculator getPacketLossCalculator() { + return new PacketLossCalculator(); + } + } + + private static long getPollIpSecStateIntervalMs( + @Nullable PersistableBundleWrapper carrierConfig) { + final int seconds; + + if (carrierConfig != null) { + seconds = + carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, + POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT); + } else { + seconds = POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT; + } + + return TimeUnit.SECONDS.toMillis(seconds); + } + + private static int getPacketLossRatePercentThreshold( + @Nullable PersistableBundleWrapper carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT); + } + return IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT; + } + + @Override + protected void onSelectedUnderlyingNetworkChanged() { + if (!isSelectedUnderlyingNetwork()) { + mInboundTransform = null; + stop(); + } + + // No action when the underlying network got selected. Wait for the inbound transform to + // start the monitor + } + + @Override + public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inboundTransform) { + Objects.requireNonNull(inboundTransform, "inboundTransform is null"); + + if (Objects.equals(inboundTransform, mInboundTransform)) { + return; + } + + if (!isSelectedUnderlyingNetwork()) { + logWtf("setInboundTransform called but network not selected"); + return; + } + + // When multiple parallel inbound transforms are created, NetworkMetricMonitor will be + // enabled on the last one as a sample + mInboundTransform = inboundTransform; + start(); + } + + @Override + public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) { + // The already scheduled event will not be affected. The followup events will be scheduled + // with the new interval + mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + } + + @Override + protected void start() { + super.start(); + clearTransformStateAndPollingEvents(); + mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L); + } + + @Override + public void stop() { + super.stop(); + clearTransformStateAndPollingEvents(); + } + + private void clearTransformStateAndPollingEvents() { + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + mLastIpSecTransformState = null; + } + + @Override + public void close() { + super.close(); + + if (mInboundTransform != null) { + mInboundTransform.close(); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @Nullable + public IpSecTransformState getLastTransformState() { + return mLastIpSecTransformState; + } + + @VisibleForTesting(visibility = Visibility.PROTECTED) + @Nullable + public IpSecTransformWrapper getInboundTransformInternal() { + return mInboundTransform; + } + + private class PollIpSecStateRunnable implements Runnable { + @Override + public void run() { + if (!isStarted()) { + logWtf("Monitor stopped but PollIpSecStateRunnable not removed from Handler"); + return; + } + + getInboundTransformInternal() + .getIpSecTransformState( + new HandlerExecutor(mHandler), new IpSecTransformStateReceiver()); + + // Schedule for next poll + mHandler.postDelayed( + new PollIpSecStateRunnable(), mCancellationToken, mPollIpSecStateIntervalMs); + } + } + + private class IpSecTransformStateReceiver + implements OutcomeReceiver { + @Override + public void onResult(@NonNull IpSecTransformState state) { + getVcnContext().ensureRunningOnLooperThread(); + + if (!isStarted()) { + return; + } + + onIpSecTransformStateReceived(state); + } + + @Override + public void onError(@NonNull RuntimeException error) { + getVcnContext().ensureRunningOnLooperThread(); + + // Nothing we can do here + logW("TransformStateReceiver#onError " + error.toString()); + } + } + + private void onIpSecTransformStateReceived(@NonNull IpSecTransformState state) { + if (mLastIpSecTransformState == null) { + // This is first time to poll the state + mLastIpSecTransformState = state; + return; + } + + final int packetLossRate = + mPacketLossCalculator.getPacketLossRatePercentage( + mLastIpSecTransformState, state, getLogPrefix()); + + if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) { + return; + } + + final String logMsg = + "packetLossRate: " + + packetLossRate + + "% in the past " + + (state.getTimestamp() - mLastIpSecTransformState.getTimestamp()) + + "ms"; + + mLastIpSecTransformState = state; + if (packetLossRate < mPacketLossRatePercentThreshold) { + logV(logMsg); + onValidationResultReceivedInternal(false /* isFailed */); + } else { + logInfo(logMsg); + onValidationResultReceivedInternal(true /* isFailed */); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class PacketLossCalculator { + /** Calculate the packet loss rate between two timestamps */ + public int getPacketLossRatePercentage( + @NonNull IpSecTransformState oldState, + @NonNull IpSecTransformState newState, + String logPrefix) { + logVIpSecTransform("oldState", oldState, logPrefix); + logVIpSecTransform("newState", newState, logPrefix); + + final int replayWindowSize = oldState.getReplayBitmap().length * 8; + final long oldSeqHi = oldState.getRxHighestSequenceNumber(); + final long oldSeqLow = Math.max(0L, oldSeqHi - replayWindowSize + 1); + final long newSeqHi = newState.getRxHighestSequenceNumber(); + final long newSeqLow = Math.max(0L, newSeqHi - replayWindowSize + 1); + + if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) { + // The replay window did not proceed and all packets might have been delivered out + // of order + return PACKET_LOSS_UNAVALAIBLE; + } + + // Get the expected packet count by assuming there is no packet loss. In this case, SA + // should receive all packets whose sequence numbers are smaller than the lower bound of + // the replay window AND the packets received within the window. + // When the lower bound is 0, it's not possible to tell whether packet with seqNo 0 is + // received or not. For simplicity just assume that packet is received. + final long newExpectedPktCnt = newSeqLow + getPacketCntInReplayWindow(newState); + final long oldExpectedPktCnt = oldSeqLow + getPacketCntInReplayWindow(oldState); + + final long expectedPktCntDiff = newExpectedPktCnt - oldExpectedPktCnt; + final long actualPktCntDiff = newState.getPacketCount() - oldState.getPacketCount(); + + logV( + TAG, + logPrefix + + " expectedPktCntDiff: " + + expectedPktCntDiff + + " actualPktCntDiff: " + + actualPktCntDiff); + + if (expectedPktCntDiff < 0 + || expectedPktCntDiff == 0 + || actualPktCntDiff < 0 + || actualPktCntDiff > expectedPktCntDiff) { + logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff"); + return PACKET_LOSS_UNAVALAIBLE; + } + + return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + } + } + + private static void logVIpSecTransform( + String transformTag, IpSecTransformState state, String logPrefix) { + final String stateString = + " seqNo: " + + state.getRxHighestSequenceNumber() + + " | pktCnt: " + + state.getPacketCount() + + " | pktCntInWindow: " + + getPacketCntInReplayWindow(state); + logV(TAG, logPrefix + " " + transformTag + stateString); + } + + /** Get the number of received packets within the replay window */ + private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) { + return BitSet.valueOf(state.getReplayBitmap()).cardinality(); + } +} diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java new file mode 100644 index 0000000000..a79f188713 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static com.android.server.VcnManagementService.LOCAL_LOG; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.IpSecTransform; +import android.net.IpSecTransformState; +import android.net.Network; +import android.os.OutcomeReceiver; +import android.util.CloseGuard; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.VcnContext; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * NetworkMetricMonitor is responsible for managing metric monitoring and tracking validation + * results. + * + *

    This class is flag gated by "network_metric_monitor" + */ +public abstract class NetworkMetricMonitor implements AutoCloseable { + private static final String TAG = NetworkMetricMonitor.class.getSimpleName(); + + private static final boolean VDBG = false; // STOPSHIP: if true + + @NonNull private final CloseGuard mCloseGuard = new CloseGuard(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final Network mNetwork; + @NonNull private final NetworkMetricMonitorCallback mCallback; + + private boolean mIsSelectedUnderlyingNetwork; + private boolean mIsStarted; + private boolean mIsValidationFailed; + + protected NetworkMetricMonitor( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) { + // Caller error + logWtf("networkMetricMonitor flag disabled"); + throw new IllegalAccessException("networkMetricMonitor flag disabled"); + } + + mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + mNetwork = Objects.requireNonNull(network, "Missing network"); + mCallback = Objects.requireNonNull(callback, "Missing callback"); + + mIsSelectedUnderlyingNetwork = false; + mIsStarted = false; + mIsValidationFailed = false; + } + + /** Callback to notify caller of the validation result */ + public interface NetworkMetricMonitorCallback { + /** Called when there is a validation result is ready */ + void onValidationResultReceived(); + } + + /** + * Start monitoring + * + *

    This method might be called on a an already started monitor for updating monitor + * properties (e.g. IpSecTransform, carrier config) + * + *

    Subclasses MUST call super.start() when overriding this method + */ + protected void start() { + mIsStarted = true; + } + + /** + * Stop monitoring + * + *

    Subclasses MUST call super.stop() when overriding this method + */ + public void stop() { + mIsValidationFailed = false; + mIsStarted = false; + } + + /** Called by the subclasses when the validation result is ready */ + protected void onValidationResultReceivedInternal(boolean isFailed) { + mIsValidationFailed = isFailed; + mCallback.onValidationResultReceived(); + } + + /** Called when the underlying network changes to selected or unselected */ + protected abstract void onSelectedUnderlyingNetworkChanged(); + + /** + * Mark the network being monitored selected or unselected + * + *

    Subclasses MUST call super when overriding this method + */ + public void setIsSelectedUnderlyingNetwork(boolean isSelectedUnderlyingNetwork) { + if (mIsSelectedUnderlyingNetwork == isSelectedUnderlyingNetwork) { + return; + } + + mIsSelectedUnderlyingNetwork = isSelectedUnderlyingNetwork; + onSelectedUnderlyingNetworkChanged(); + } + + /** Wrapper that allows injection for testing purposes */ + @VisibleForTesting(visibility = Visibility.PROTECTED) + public static class IpSecTransformWrapper { + @NonNull public final IpSecTransform ipSecTransform; + + public IpSecTransformWrapper(@NonNull IpSecTransform ipSecTransform) { + this.ipSecTransform = ipSecTransform; + } + + /** Poll an IpSecTransformState */ + public void getIpSecTransformState( + @NonNull Executor executor, + @NonNull OutcomeReceiver callback) { + ipSecTransform.getIpSecTransformState(executor, callback); + } + + /** Close this instance and release the underlying resources */ + public void close() { + ipSecTransform.close(); + } + + @Override + public int hashCode() { + return Objects.hash(ipSecTransform); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpSecTransformWrapper)) { + return false; + } + + final IpSecTransformWrapper other = (IpSecTransformWrapper) o; + + return Objects.equals(ipSecTransform, other.ipSecTransform); + } + } + + /** Set the IpSecTransform that applied to the Network being monitored */ + public void setInboundTransform(@NonNull IpSecTransform inTransform) { + setInboundTransformInternal(new IpSecTransformWrapper(inTransform)); + } + + /** + * Set the IpSecTransform that applied to the Network being monitored * + * + *

    Subclasses MUST call super when overriding this method + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inTransform) { + // Subclasses MUST override it if they care + } + + /** Update the carrierconfig */ + public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) { + // Subclasses MUST override it if they care + } + + public boolean isValidationFailed() { + return mIsValidationFailed; + } + + public boolean isSelectedUnderlyingNetwork() { + return mIsSelectedUnderlyingNetwork; + } + + public boolean isStarted() { + return mIsStarted; + } + + @NonNull + public VcnContext getVcnContext() { + return mVcnContext; + } + + // Override methods for AutoCloseable. Subclasses MUST call super when overriding this method + @Override + public void close() { + mCloseGuard.close(); + + stop(); + } + + // Override #finalize() to use closeGuard for flagging that #close() was not called + @SuppressWarnings("Finalize") + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } finally { + super.finalize(); + } + } + + private String getClassName() { + return this.getClass().getSimpleName(); + } + + protected String getLogPrefix() { + return " [Network " + mNetwork + "] "; + } + + protected void logV(String msg) { + if (VDBG) { + Slog.v(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[VERBOSE ] " + getClassName() + getLogPrefix() + msg); + } + } + + protected void logInfo(String msg) { + Slog.i(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[INFO ] " + getClassName() + getLogPrefix() + msg); + } + + protected void logW(String msg) { + Slog.w(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[WARN ] " + getClassName() + getLogPrefix() + msg); + } + + protected void logWtf(String msg) { + Slog.wtf(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[WTF ] " + getClassName() + getLogPrefix() + msg); + } + + protected static void logV(String className, String msgWithPrefix) { + if (VDBG) { + Slog.wtf(className, msgWithPrefix); + LOCAL_LOG.log("[VERBOSE ] " + className + msgWithPrefix); + } + } + + protected static void logWtf(String className, String msgWithPrefix) { + Slog.wtf(className, msgWithPrefix); + LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java new file mode 100644 index 0000000000..9daba6a79a --- /dev/null +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn.routeselection; + +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; + +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.net.IpSecTransformState; +import android.os.OutcomeReceiver; +import android.os.PowerManager; + +import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator; +import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper; +import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Spy; + +import java.util.Arrays; +import java.util.BitSet; +import java.util.concurrent.TimeUnit; + +public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { + private static final String TAG = IpSecPacketLossDetectorTest.class.getSimpleName(); + + private static final int REPLAY_BITMAP_LEN_BYTE = 512; + private static final int REPLAY_BITMAP_LEN_BIT = REPLAY_BITMAP_LEN_BYTE * 8; + private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD = 5; + private static final long POLL_IPSEC_STATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(30L); + + @Mock private IpSecTransformWrapper mIpSecTransform; + @Mock private NetworkMetricMonitorCallback mMetricMonitorCallback; + @Mock private PersistableBundleWrapper mCarrierConfig; + @Mock private IpSecPacketLossDetector.Dependencies mDependencies; + @Spy private PacketLossCalculator mPacketLossCalculator = new PacketLossCalculator(); + + @Captor private ArgumentCaptor mTransformStateReceiverCaptor; + @Captor private ArgumentCaptor mBroadcastReceiverCaptor; + + private IpSecPacketLossDetector mIpSecPacketLossDetector; + private IpSecTransformState mTransformStateInitial; + + @Before + public void setUp() throws Exception { + super.setUp(); + mTransformStateInitial = newTransformState(0, 0, newReplayBitmap(0)); + + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt())) + .thenReturn((int) TimeUnit.MILLISECONDS.toSeconds(POLL_IPSEC_STATE_INTERVAL_MS)); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), + anyInt())) + .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + + when(mDependencies.getPacketLossCalculator()).thenReturn(mPacketLossCalculator); + + mIpSecPacketLossDetector = + new IpSecPacketLossDetector( + mVcnContext, + mNetwork, + mCarrierConfig, + mMetricMonitorCallback, + mDependencies); + } + + private static IpSecTransformState newTransformState( + long rxSeqNo, long packtCount, byte[] replayBitmap) { + return new IpSecTransformState.Builder() + .setRxHighestSequenceNumber(rxSeqNo) + .setPacketCount(packtCount) + .setReplayBitmap(replayBitmap) + .build(); + } + + private static byte[] newReplayBitmap(int receivedPktCnt) { + final BitSet bitSet = new BitSet(REPLAY_BITMAP_LEN_BIT); + for (int i = 0; i < receivedPktCnt; i++) { + bitSet.set(i); + } + return Arrays.copyOf(bitSet.toByteArray(), REPLAY_BITMAP_LEN_BYTE); + } + + private void verifyStopped() { + assertFalse(mIpSecPacketLossDetector.isStarted()); + assertFalse(mIpSecPacketLossDetector.isValidationFailed()); + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + + // No event scheduled + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testInitialization() throws Exception { + assertFalse(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork()); + verifyStopped(); + } + + private OutcomeReceiver + startMonitorAndCaptureStateReceiver() { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + // Trigger the runnable + mTestLooper.dispatchAll(); + + verify(mIpSecTransform) + .getIpSecTransformState(any(), mTransformStateReceiverCaptor.capture()); + return mTransformStateReceiverCaptor.getValue(); + } + + @Test + public void testStartMonitor() throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertFalse(mIpSecPacketLossDetector.isValidationFailed()); + assertTrue(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork()); + assertEquals(mIpSecTransform, mIpSecPacketLossDetector.getInboundTransformInternal()); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + + // Verify the first polled state is stored + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + + // Verify next poll is scheduled + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNotNull(mTestLooper.nextMessage()); + } + + @Test + public void testStartedMonitor_enterDozeMoze() throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + + // Mock entering doze mode + final Intent intent = mock(Intent.class); + when(intent.getAction()).thenReturn(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + when(mPowerManagerService.isDeviceIdleMode()).thenReturn(true); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any(), any(), any()); + final BroadcastReceiver broadcastReceiver = mBroadcastReceiverCaptor.getValue(); + broadcastReceiver.onReceive(mContext, intent); + + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + } + + @Test + public void testStartedMonitor_updateInboundTransform() throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + + // Update the inbound transform + final IpSecTransformWrapper newTransform = mock(IpSecTransformWrapper.class); + mIpSecPacketLossDetector.setInboundTransformInternal(newTransform); + + // Verifications + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + mTestLooper.dispatchAll(); + verify(newTransform).getIpSecTransformState(any(), any()); + } + + @Test + public void testStartedMonitor_updateCarrierConfig() throws Exception { + startMonitorAndCaptureStateReceiver(); + + final int additionalPollIntervalMs = (int) TimeUnit.SECONDS.toMillis(10L); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt())) + .thenReturn( + (int) + TimeUnit.MILLISECONDS.toSeconds( + POLL_IPSEC_STATE_INTERVAL_MS + additionalPollIntervalMs)); + mIpSecPacketLossDetector.setCarrierConfig(mCarrierConfig); + mTestLooper.dispatchAll(); + + // The already scheduled event is still fired with the old timeout + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + mTestLooper.dispatchAll(); + + // The next scheduled event will take 10 more seconds to fire + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(additionalPollIntervalMs); + assertNotNull(mTestLooper.nextMessage()); + } + + @Test + public void testStopMonitor() throws Exception { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertNotNull(mTestLooper.nextMessage()); + + // Unselect the monitor + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */); + verifyStopped(); + } + + @Test + public void testClose() throws Exception { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertNotNull(mTestLooper.nextMessage()); + + // Stop the monitor + mIpSecPacketLossDetector.close(); + verifyStopped(); + verify(mIpSecTransform).close(); + } + + @Test + public void testTransformStateReceiverOnResultWhenStopped() throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + xfrmStateReceiver.onResult(mTransformStateInitial); + + // Unselect the monitor + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */); + verifyStopped(); + + xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1))); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + } + + @Test + public void testTransformStateReceiverOnError() throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + xfrmStateReceiver.onResult(mTransformStateInitial); + + xfrmStateReceiver.onError(new RuntimeException("Test")); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + } + + private void checkHandleLossRate( + int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected) + throws Exception { + final OutcomeReceiver xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + doReturn(mockPacketLossRate) + .when(mPacketLossCalculator) + .getPacketLossRatePercentage(any(), any(), anyString()); + + // Mock receiving two states with mTransformStateInitial and an arbitrary transformNew + final IpSecTransformState transformNew = newTransformState(1, 1, newReplayBitmap(1)); + xfrmStateReceiver.onResult(mTransformStateInitial); + xfrmStateReceiver.onResult(transformNew); + + // Verifications + verify(mPacketLossCalculator) + .getPacketLossRatePercentage( + eq(mTransformStateInitial), eq(transformNew), anyString()); + + if (isLastStateExpectedToUpdate) { + assertEquals(transformNew, mIpSecPacketLossDetector.getLastTransformState()); + } else { + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + } + + if (isCallbackExpected) { + verify(mMetricMonitorCallback).onValidationResultReceived(); + } else { + verify(mMetricMonitorCallback, never()).onValidationResultReceived(); + } + } + + @Test + public void testHandleLossRate_validationPass() throws Exception { + checkHandleLossRate( + 2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_validationFail() throws Exception { + checkHandleLossRate( + 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_resultUnavalaible() throws Exception { + checkHandleLossRate( + PACKET_LOSS_UNAVALAIBLE, + false /* isLastStateExpectedToUpdate */, + false /* isCallbackExpected */); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate) + throws Exception { + assertEquals( + expectedLossRate, + mPacketLossCalculator.getPacketLossRatePercentage(oldState, newState, TAG)); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, + int rxSeqNo, + int packetCount, + int packetInWin, + int expectedDataLossRate) + throws Exception { + final IpSecTransformState newState = + newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); + checkGetPacketLossRate(oldState, newState, expectedDataLossRate); + } + + @Test + public void testGetPacketLossRate_replayWindowUnchanged() throws Exception { + checkGetPacketLossRate( + mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE); + checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE); + } + + @Test + public void testGetPacketLossRate_againstInitialState() throws Exception { + checkGetPacketLossRate(mTransformStateInitial, 7000, 7001, 4096, 0); + checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4096, 15); + checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4000, 14); + } + + @Test + public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_overlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500)); + + checkGetPacketLossRate(oldState, 5000, 5001, 4096, 0); + checkGetPacketLossRate(oldState, 5000, 4000, 4096, 29); + checkGetPacketLossRate(oldState, 5000, 4000, 4000, 27); + } + + @Test + public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_notOverlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500)); + + checkGetPacketLossRate(oldState, 7000, 7001, 4096, 0); + checkGetPacketLossRate(oldState, 7000, 5000, 4096, 37); + checkGetPacketLossRate(oldState, 7000, 5000, 3000, 21); + } + + @Test + public void testGetPktLossRate_oldHiSeqLargerThanWinSize_overlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000)); + + checkGetPacketLossRate(oldState, 12000, 8096, 4096, 0); + checkGetPacketLossRate(oldState, 12000, 7000, 4096, 36); + checkGetPacketLossRate(oldState, 12000, 7000, 3000, 0); + } + + @Test + public void testGetPktLossRate_oldHiSeqLargerThanWinSize_notOverlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000)); + + checkGetPacketLossRate(oldState, 20000, 16096, 4096, 0); + checkGetPacketLossRate(oldState, 20000, 14000, 4096, 19); + checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10); + } +} diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index bf84bbeeed..355c22156a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -20,6 +20,7 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -29,7 +30,12 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.FeatureFlags; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; import android.os.ParcelUuid; +import android.os.PowerManager; import android.os.test.TestLooper; import android.telephony.TelephonyManager; @@ -90,32 +96,49 @@ public abstract class NetworkEvaluationTestBase { protected static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); + @Mock protected Context mContext; @Mock protected Network mNetwork; + @Mock protected FeatureFlags mFeatureFlags; + @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected TelephonyManager mTelephonyManager; + @Mock protected IPowerManager mPowerManagerService; protected TestLooper mTestLooper; protected VcnContext mVcnContext; + protected PowerManager mPowerManager; @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - final Context mockContext = mock(Context.class); + when(mNetwork.getNetId()).thenReturn(-1); + mTestLooper = new TestLooper(); mVcnContext = spy( new VcnContext( - mockContext, + mContext, mTestLooper.getLooper(), mock(VcnNetworkProvider.class), false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); + doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); + setupSystemService( - mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); + + mPowerManager = + new PowerManager( + mContext, + mPowerManagerService, + mock(IThermalService.class), + mock(Handler.class)); + setupSystemService(mContext, mPowerManager, Context.POWER_SERVICE, PowerManager.class); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index dbf2f514fe..d85c5150f5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -57,7 +57,7 @@ public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase { private UnderlyingNetworkRecord mCellNetworkRecord; @Before - public void setUp() { + public void setUp() throws Exception { super.setUp(); mWifiNetworkRecord = getTestNetworkRecord(WIFI_NETWORK_CAPABILITIES); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java index a4567ddc20..985e70c977 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -34,7 +34,7 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { private PersistableBundleWrapper mCarrierConfig; @Before - public void setUp() { + public void setUp() throws Exception { super.setUp(); mCarrierConfig = new PersistableBundleWrapper(new PersistableBundle()); } From ddcf238d5e7b8a1e53974a027e10eaebad755d22 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 13 Dec 2023 23:48:55 +0000 Subject: [PATCH 0402/1057] Enable NetworkMetricMonitor and support penalizing networks This CL integrates the IpSecPacketLossDetector into VCN route selection. With this change, when a data stall is reported, the network candidate will be penalized and then deprioritized during network selection. A network candidate will stop being penalized until it hitting a timeout or passing the validation. Bug: 282996138 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: Ifabd6fdea1d5a4fea40cf929dbab7c26d37274ac --- .../src/android/net/vcn/VcnManager.java | 14 +- .../server/vcn/VcnGatewayConnection.java | 6 + .../UnderlyingNetworkController.java | 73 +++++- .../UnderlyingNetworkEvaluator.java | 229 ++++++++++++++++- ...cnGatewayConnectionConnectedStateTest.java | 3 + .../vcn/VcnGatewayConnectionTestBase.java | 2 + .../NetworkEvaluationTestBase.java | 6 + .../UnderlyingNetworkControllerTest.java | 79 +++++- .../UnderlyingNetworkEvaluatorTest.java | 241 +++++++++++++++++- 9 files changed, 625 insertions(+), 28 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 561db9c8a8..83b7edaec7 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -80,8 +80,6 @@ public class VcnManager { *

    The VCN will only migrate to a Carrier WiFi network that has a signal strength greater * than, or equal to this threshold. * - *

    WARNING: The VCN does not listen for changes to this key made after VCN startup. - * * @hide */ @NonNull @@ -94,8 +92,6 @@ public class VcnManager { *

    If the VCN's selected Carrier WiFi network has a signal strength less than this threshold, * the VCN will attempt to migrate away from the Carrier WiFi network. * - *

    WARNING: The VCN does not listen for changes to this key made after VCN startup. - * * @hide */ @NonNull @@ -120,6 +116,15 @@ public class VcnManager { public static final String VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY = "vcn_network_selection_ipsec_packet_loss_percent_threshold"; + /** + * Key for the list of timeouts in minute to stop penalizing an underlying network candidate + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY = + "vcn_network_selection_penalty_timeout_minutes_list"; + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz /** @@ -168,6 +173,7 @@ public class VcnManager { VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index fcc0de1c22..3094b18209 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1910,6 +1910,12 @@ public class VcnGatewayConnection extends StateMachine { // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); + if (direction == IpSecManager.DIRECTION_IN + && mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform); + } + // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as // needed) final Set exposedCaps = mConnectionConfig.getAllExposedCapabilities(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 48df44b7c4..3f8d39e72e 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -52,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; @@ -201,6 +203,14 @@ public class UnderlyingNetworkController { NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback; List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); + + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.close(); + } + } + mUnderlyingNetworkRecords.clear(); // Register new callbacks. Make-before-break; always register new callbacks before removal @@ -417,11 +427,42 @@ public class UnderlyingNetworkController { if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { + + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + reevaluateNetworks(); + } return; } registerOrUpdateNetworkRequests(); } + /** + * Pass the IpSecTransform of the VCN to UnderlyingNetworkController for metric monitoring + * + *

    Caller MUST call it when IpSecTransforms have been created for VCN creation or migration + */ + public void updateInboundTransform( + @NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) { + if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() + || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + logWtf("#updateInboundTransform: unexpected call; flags missing"); + return; + } + + Objects.requireNonNull(currentNetwork, "currentNetwork is null"); + Objects.requireNonNull(transform, "transform is null"); + + if (mCurrentRecord == null + || mRouteSelectionCallback == null + || !Objects.equals(currentNetwork.network, mCurrentRecord.network)) { + // The caller (VcnGatewayConnection) is out-of-dated. Ignore this call. + return; + } + + mUnderlyingNetworkRecords.get(mCurrentRecord.network).setInboundTransform(transform); + } + /** Tears down this Tracker, and releases all underlying network requests. */ public void teardown() { mVcnContext.ensureRunningOnLooperThread(); @@ -438,7 +479,7 @@ public class UnderlyingNetworkController { private TreeSet getSortedUnderlyingNetworks() { TreeSet sorted = - new TreeSet<>(UnderlyingNetworkEvaluator.getComparator()); + new TreeSet<>(UnderlyingNetworkEvaluator.getComparator(mVcnContext)); for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { if (evaluator.getPriorityClass() != NetworkPriorityClassifier.PRIORITY_INVALID) { @@ -525,11 +566,17 @@ public class UnderlyingNetworkController { mConnectionConfig.getVcnUnderlyingNetworkPriorities(), mSubscriptionGroup, mLastSnapshot, - mCarrierConfig)); + mCarrierConfig, + new NetworkEvaluatorCallbackImpl())); } @Override public void onLost(@NonNull Network network) { + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + mUnderlyingNetworkRecords.get(network).close(); + } + mUnderlyingNetworkRecords.remove(network); reevaluateNetworks(); @@ -598,6 +645,21 @@ public class UnderlyingNetworkController { } } + @VisibleForTesting + class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback { + @Override + public void onEvaluationResultChanged() { + if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() + || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + logWtf("#onEvaluationResultChanged: unexpected call; flags missing"); + return; + } + + mVcnContext.ensureRunningOnLooperThread(); + reevaluateNetworks(); + } + } + private String getLogPrefix() { return "(" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -690,21 +752,22 @@ public class UnderlyingNetworkController { @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { - /** Construct a new UnderlyingNetworkEvaluator */ public UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator( @NonNull VcnContext vcnContext, @NonNull Network network, @NonNull List underlyingNetworkTemplates, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot lastSnapshot, - @Nullable PersistableBundleWrapper carrierConfig) { + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback) { return new UnderlyingNetworkEvaluator( vcnContext, network, underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, - carrierConfig); + carrierConfig, + evaluatorCallback); } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index c124a1976a..2f4cf5e5d8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -16,23 +16,32 @@ package com.android.server.vcn.routeselection; +import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.os.Handler; import android.os.ParcelUuid; +import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * UnderlyingNetworkEvaluator evaluates the quality and priority class of a network candidate for @@ -43,20 +52,41 @@ import java.util.Objects; public class UnderlyingNetworkEvaluator { private static final String TAG = UnderlyingNetworkEvaluator.class.getSimpleName(); + private static final int[] PENALTY_TIMEOUT_MINUTES_DEFAULT = new int[] {5}; + @NonNull private final VcnContext mVcnContext; + @NonNull private final Handler mHandler; + @NonNull private final Object mCancellationToken = new Object(); + @NonNull private final UnderlyingNetworkRecord.Builder mNetworkRecordBuilder; + @NonNull private final NetworkEvaluatorCallback mEvaluatorCallback; + @NonNull private final List mMetricMonitors = new ArrayList<>(); + + @NonNull private final Dependencies mDependencies; + + // TODO: Support back-off timeouts + private long mPenalizedTimeoutMs; + private boolean mIsSelected; + private boolean mIsPenalized; private int mPriorityClass = NetworkPriorityClassifier.PRIORITY_INVALID; + @VisibleForTesting(visibility = Visibility.PRIVATE) public UnderlyingNetworkEvaluator( @NonNull VcnContext vcnContext, @NonNull Network network, @NonNull List underlyingNetworkTemplates, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot lastSnapshot, - @Nullable PersistableBundleWrapper carrierConfig) { + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback, + @NonNull Dependencies dependencies) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + mHandler = new Handler(mVcnContext.getLooper()); + + mDependencies = Objects.requireNonNull(dependencies, "Missing dependencies"); + mEvaluatorCallback = Objects.requireNonNull(evaluatorCallback, "Missing deps"); Objects.requireNonNull(underlyingNetworkTemplates, "Missing underlyingNetworkTemplates"); Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); @@ -66,9 +96,76 @@ public class UnderlyingNetworkEvaluator { new UnderlyingNetworkRecord.Builder( Objects.requireNonNull(network, "Missing network")); mIsSelected = false; + mIsPenalized = false; + mPenalizedTimeoutMs = getPenaltyTimeoutMs(carrierConfig); updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + if (isIpSecPacketLossDetectorEnabled()) { + try { + mMetricMonitors.add( + mDependencies.newIpSecPacketLossDetector( + mVcnContext, + mNetworkRecordBuilder.getNetwork(), + carrierConfig, + new MetricMonitorCallbackImpl())); + } catch (IllegalAccessException e) { + // No action. Do not add anything to mMetricMonitors + } + } + } + + public UnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback) { + this( + vcnContext, + network, + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + carrierConfig, + evaluatorCallback, + new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Get an IpSecPacketLossDetector instance */ + public IpSecPacketLossDetector newIpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitor.NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + return new IpSecPacketLossDetector(vcnContext, network, carrierConfig, callback); + } + } + + /** Callback to notify caller to reevaluate network selection */ + public interface NetworkEvaluatorCallback { + /** + * Called when mIsPenalized changed + * + *

    When receiving this call, UnderlyingNetworkController should reevaluate all network + * candidates for VCN underlying network selection + */ + void onEvaluationResultChanged(); + } + + private class MetricMonitorCallbackImpl + implements NetworkMetricMonitor.NetworkMetricMonitorCallback { + public void onValidationResultReceived() { + mVcnContext.ensureRunningOnLooperThread(); + + handleValidationResult(); + } } private void updatePriorityClass( @@ -91,8 +188,25 @@ public class UnderlyingNetworkEvaluator { } } - public static Comparator getComparator() { + private boolean isIpSecPacketLossDetectorEnabled() { + return isIpSecPacketLossDetectorEnabled(mVcnContext); + } + + private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) { + return vcnContext.isFlagIpSecTransformStateEnabled() + && vcnContext.isFlagNetworkMetricMonitorEnabled(); + } + + /** Get the comparator for UnderlyingNetworkEvaluator */ + public static Comparator getComparator(VcnContext vcnContext) { return (left, right) -> { + if (isIpSecPacketLossDetectorEnabled(vcnContext)) { + if (left.mIsPenalized != right.mIsPenalized) { + // A penalized network should have lower priority which means a larger index + return left.mIsPenalized ? 1 : -1; + } + } + final int leftIndex = left.mPriorityClass; final int rightIndex = right.mPriorityClass; @@ -112,6 +226,64 @@ public class UnderlyingNetworkEvaluator { }; } + private static long getPenaltyTimeoutMs(@Nullable PersistableBundleWrapper carrierConfig) { + final int[] timeoutMinuteList; + + if (carrierConfig != null) { + timeoutMinuteList = + carrierConfig.getIntArray( + VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, + PENALTY_TIMEOUT_MINUTES_DEFAULT); + } else { + timeoutMinuteList = PENALTY_TIMEOUT_MINUTES_DEFAULT; + } + + // TODO: Add the support of back-off timeouts and return the full list + return TimeUnit.MINUTES.toMillis(timeoutMinuteList[0]); + } + + private void handleValidationResult() { + final boolean wasPenalized = mIsPenalized; + mIsPenalized = false; + for (NetworkMetricMonitor monitor : mMetricMonitors) { + mIsPenalized |= monitor.isValidationFailed(); + } + + if (wasPenalized == mIsPenalized) { + return; + } + + logInfo( + "#handleValidationResult: wasPenalized " + + wasPenalized + + " mIsPenalized " + + mIsPenalized); + + if (mIsPenalized) { + mHandler.postDelayed( + new ExitPenaltyBoxRunnable(), mCancellationToken, mPenalizedTimeoutMs); + } else { + // Exit the penalty box + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + } + mEvaluatorCallback.onEvaluationResultChanged(); + } + + public class ExitPenaltyBoxRunnable implements Runnable { + @Override + public void run() { + if (!mIsPenalized) { + logWtf("Evaluator not being penalized but ExitPenaltyBoxRunnable was scheduled"); + return; + } + + // TODO: There might be a future metric monitor (e.g. ping) that will require the + // validation to pass before exiting the penalty box. + mIsPenalized = false; + mEvaluatorCallback.onEvaluationResultChanged(); + } + } + /** Set the NetworkCapabilities */ public void setNetworkCapabilities( @NonNull NetworkCapabilities nc, @@ -162,6 +334,10 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setIsSelectedUnderlyingNetwork(isSelected); + } } /** @@ -174,6 +350,35 @@ public class UnderlyingNetworkEvaluator { @Nullable PersistableBundleWrapper carrierConfig) { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + // The already scheduled event will not be affected. The followup events will be scheduled + // with the new timeout + mPenalizedTimeoutMs = getPenaltyTimeoutMs(carrierConfig); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setCarrierConfig(carrierConfig); + } + } + + /** Update the inbound IpSecTransform applied to the network */ + public void setInboundTransform(@NonNull IpSecTransform transform) { + if (!mIsSelected) { + logWtf("setInboundTransform on an unselected evaluator"); + return; + } + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setInboundTransform(transform); + } + } + + /** Close the evaluator and stop all the underlying network metric monitors */ + public void close() { + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.close(); + } } /** Return whether this network evaluator is valid */ @@ -196,6 +401,11 @@ public class UnderlyingNetworkEvaluator { return mPriorityClass; } + /** Return whether the network is being penalized */ + public boolean isPenalized() { + return mIsPenalized; + } + /** Dump the information of this instance */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkEvaluator:"); @@ -211,7 +421,22 @@ public class UnderlyingNetworkEvaluator { pw.println("mIsSelected: " + mIsSelected); pw.println("mPriorityClass: " + mPriorityClass); + pw.println("mIsPenalized: " + mIsPenalized); pw.decreaseIndent(); } + + private String getLogPrefix() { + return "[Network " + mNetworkRecordBuilder.getNetwork() + "] "; + } + + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[INFO ] " + TAG + getLogPrefix() + msg); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[WTF ] " + TAG + getLogPrefix() + msg); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index f846164263..20b7f1f146 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -269,6 +269,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testCreatedTransformsAreApplied() throws Exception { verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */); + verify(mUnderlyingNetworkController).updateInboundTransform(any(), any()); } @Test @@ -327,6 +328,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } + verify(mUnderlyingNetworkController).updateInboundTransform(any(), any()); + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List saProposals = diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 4c7b25aaa7..e29e4621d5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -223,6 +223,8 @@ public class VcnGatewayConnectionTestBase { doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); + doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); + doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 355c22156a..6015e93184 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -26,6 +26,8 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.IpSecConfig; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -141,4 +143,8 @@ public abstract class NetworkEvaluationTestBase { mock(Handler.class)); setupSystemService(mContext, mPowerManager, Context.POWER_SERVICE, PowerManager.class); } + + protected IpSecTransform makeDummyIpSecTransform() throws Exception { + return new IpSecTransform(mContext, new IpSecConfig()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 992f102757..588624b562 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -47,6 +47,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; +import android.net.IpSecConfig; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -70,6 +72,7 @@ import com.android.server.vcn.routeselection.UnderlyingNetworkController.Depende import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; import org.junit.Before; import org.junit.Test; @@ -153,11 +156,13 @@ public class UnderlyingNetworkControllerTest { @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb; + @Mock private NetworkEvaluatorCallback mEvaluatorCallback; @Mock private Network mNetwork; @Spy private Dependencies mDependencies = new Dependencies(); @Captor private ArgumentCaptor mUnderlyingNetworkListenerCaptor; + @Captor private ArgumentCaptor mEvaluatorCallbackCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; @@ -176,7 +181,7 @@ public class UnderlyingNetworkControllerTest { mTestLooper.getLooper(), mVcnNetworkProvider, false /* isInTestMode */)); - resetVcnContext(); + resetVcnContext(mVcnContext); setupSystemService( mContext, @@ -202,10 +207,11 @@ public class UnderlyingNetworkControllerTest { .getVcnUnderlyingNetworkPriorities(), SUB_GROUP, mSubscriptionSnapshot, - null)); + null, + mEvaluatorCallback)); doReturn(mNetworkEvaluator) .when(mDependencies) - .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any()); + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any(), any()); mUnderlyingNetworkController = new UnderlyingNetworkController( @@ -217,9 +223,11 @@ public class UnderlyingNetworkControllerTest { mDependencies); } - private void resetVcnContext() { - reset(mVcnContext); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + private void resetVcnContext(VcnContext vcnContext) { + reset(vcnContext); + doNothing().when(vcnContext).ensureRunningOnLooperThread(); + doReturn(true).when(vcnContext).isFlagNetworkMetricMonitorEnabled(); + doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled(); } // Package private for use in NetworkPriorityClassifierTest @@ -245,11 +253,13 @@ public class UnderlyingNetworkControllerTest { final ConnectivityManager cm = mock(ConnectivityManager.class); setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); final VcnContext vcnContext = - new VcnContext( - mContext, - mTestLooper.getLooper(), - mVcnNetworkProvider, - true /* isInTestMode */); + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */)); + resetVcnContext(vcnContext); new UnderlyingNetworkController( vcnContext, @@ -554,6 +564,45 @@ public class UnderlyingNetworkControllerTest { verify(mNetworkEvaluator).reevaluate(any(), any(), any(), any()); } + @Test + public void testUpdateIpSecTransform() { + verifyRegistrationOnAvailableAndGetCallback(); + + final UnderlyingNetworkRecord expectedRecord = + getTestNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + final IpSecTransform expectedTransform = new IpSecTransform(mContext, new IpSecConfig()); + + mUnderlyingNetworkController.updateInboundTransform(expectedRecord, expectedTransform); + verify(mNetworkEvaluator).setInboundTransform(expectedTransform); + } + + @Test + public void testOnEvaluationResultChanged() { + verifyRegistrationOnAvailableAndGetCallback(); + + // Verify #reevaluateNetworks is called by checking #getNetworkRecord + verify(mNetworkEvaluator).getNetworkRecord(); + + // Trigger the callback + verify(mDependencies) + .newUnderlyingNetworkEvaluator( + any(), + any(), + any(), + any(), + any(), + any(), + mEvaluatorCallbackCaptor.capture()); + mEvaluatorCallbackCaptor.getValue().onEvaluationResultChanged(); + + // Verify #reevaluateNetworks is called again + verify(mNetworkEvaluator, times(2)).getNetworkRecord(); + } + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } @@ -682,7 +731,7 @@ public class UnderlyingNetworkControllerTest { cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); - verifyOnSelectedUnderlyingNetworkChanged(null); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); } @Test @@ -690,6 +739,7 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLost(mNetwork); + verify(mNetworkEvaluator).close(); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); } @@ -755,10 +805,11 @@ public class UnderlyingNetworkControllerTest { underlyingNetworkTemplates, SUB_GROUP, mSubscriptionSnapshot, - null)); + null, + mEvaluatorCallback)); doReturn(evaluator) .when(mDependencies) - .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any()); + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any(), any()); cb.onAvailable(network); cb.onCapabilitiesChanged(network, responseNetworkCaps); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java index 985e70c977..aa81efe9a1 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -16,27 +16,65 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY; + import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; 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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.net.IpSecTransform; import android.net.vcn.VcnGatewayConnectionConfig; -import android.os.PersistableBundle; + +import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.Dependencies; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; + +import java.util.concurrent.TimeUnit; public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { - private PersistableBundleWrapper mCarrierConfig; + private static final int PENALTY_TIMEOUT_MIN = 10; + private static final long PENALTY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(PENALTY_TIMEOUT_MIN); + + @Mock private PersistableBundleWrapper mCarrierConfig; + @Mock private IpSecPacketLossDetector mIpSecPacketLossDetector; + @Mock private Dependencies mDependencies; + @Mock private NetworkEvaluatorCallback mEvaluatorCallback; + + @Captor private ArgumentCaptor mMetricMonitorCbCaptor; + + private UnderlyingNetworkEvaluator mNetworkEvaluator; @Before public void setUp() throws Exception { super.setUp(); - mCarrierConfig = new PersistableBundleWrapper(new PersistableBundle()); + + when(mDependencies.newIpSecPacketLossDetector(any(), any(), any(), any())) + .thenReturn(mIpSecPacketLossDetector); + + when(mCarrierConfig.getIntArray( + eq(VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY), anyObject())) + .thenReturn(new int[] {PENALTY_TIMEOUT_MIN}); + + mNetworkEvaluator = newValidUnderlyingNetworkEvaluator(); } private UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator() { @@ -46,7 +84,34 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, SUB_GROUP, mSubscriptionSnapshot, + mCarrierConfig, + mEvaluatorCallback, + mDependencies); + } + + private UnderlyingNetworkEvaluator newValidUnderlyingNetworkEvaluator() { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + + evaluator.setNetworkCapabilities( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, mCarrierConfig); + evaluator.setLinkProperties( + LINK_PROPERTIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setIsBlocked( + false /* isBlocked */, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + return evaluator; } @Test @@ -98,4 +163,174 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { assertEquals(2, evaluator.getPriorityClass()); assertEquals(expectedRecord, evaluator.getNetworkRecord()); } + + private void checkSetSelectedNetwork(boolean isSelected) { + mNetworkEvaluator.setIsSelected( + isSelected, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + verify(mIpSecPacketLossDetector).setIsSelectedUnderlyingNetwork(isSelected); + } + + @Test + public void testSetIsSelected_selected() throws Exception { + checkSetSelectedNetwork(true /* isSelectedExpected */); + } + + @Test + public void testSetIsSelected_unselected() throws Exception { + checkSetSelectedNetwork(false /* isSelectedExpected */); + } + + @Test + public void testSetIpSecTransform_onSelectedNetwork() throws Exception { + final IpSecTransform transform = makeDummyIpSecTransform(); + + // Make the network selected + mNetworkEvaluator.setIsSelected( + true, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + mNetworkEvaluator.setInboundTransform(transform); + + verify(mIpSecPacketLossDetector).setInboundTransform(transform); + } + + @Test + public void testSetIpSecTransform_onUnSelectedNetwork() throws Exception { + mNetworkEvaluator.setIsSelected( + false, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + mNetworkEvaluator.setInboundTransform(makeDummyIpSecTransform()); + + verify(mIpSecPacketLossDetector, never()).setInboundTransform(any()); + } + + @Test + public void close() throws Exception { + mNetworkEvaluator.close(); + + verify(mIpSecPacketLossDetector).close(); + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + private NetworkMetricMonitorCallback getMetricMonitorCbCaptor() throws Exception { + verify(mDependencies) + .newIpSecPacketLossDetector(any(), any(), any(), mMetricMonitorCbCaptor.capture()); + + return mMetricMonitorCbCaptor.getValue(); + } + + private void checkPenalizeNetwork() throws Exception { + assertFalse(mNetworkEvaluator.isPenalized()); + + // Validation failed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(true); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verify the evaluator is penalized + assertTrue(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback).onEvaluationResultChanged(); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_penaltyTimeout() throws Exception { + checkPenalizeNetwork(); + + // Penalty timeout + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + mTestLooper.dispatchAll(); + + // Verify the evaluator is not penalized + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, times(2)).onEvaluationResultChanged(); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_passValidation() throws Exception { + checkPenalizeNetwork(); + + // Validation passed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(false); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verify the evaluator is not penalized and penalty timeout is canceled + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, times(2)).onEvaluationResultChanged(); + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_closeEvaluator() throws Exception { + checkPenalizeNetwork(); + + mNetworkEvaluator.close(); + + // Verify penalty timeout is canceled + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testRcvValidationResult_PenaltyStateUnchanged() throws Exception { + assertFalse(mNetworkEvaluator.isPenalized()); + + // Validation passed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(false); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verifications + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, never()).onEvaluationResultChanged(); + } + + @Test + public void testSetCarrierConfig() throws Exception { + final int additionalTimeoutMin = 10; + when(mCarrierConfig.getIntArray( + eq(VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY), anyObject())) + .thenReturn(new int[] {PENALTY_TIMEOUT_MIN + additionalTimeoutMin}); + + // Update evaluator and penalize the network + mNetworkEvaluator.reevaluate( + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + checkPenalizeNetwork(); + + // Verify penalty timeout is changed + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(TimeUnit.MINUTES.toMillis(additionalTimeoutMin)); + assertNotNull(mTestLooper.nextMessage()); + + // Verify NetworkMetricMonitor is notified + verify(mIpSecPacketLossDetector).setCarrierConfig(any()); + } + + @Test + public void testCompare() throws Exception { + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(true); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + final UnderlyingNetworkEvaluator penalized = mNetworkEvaluator; + final UnderlyingNetworkEvaluator notPenalized = newValidUnderlyingNetworkEvaluator(); + + assertEquals(penalized.getPriorityClass(), notPenalized.getPriorityClass()); + + final int result = + UnderlyingNetworkEvaluator.getComparator(mVcnContext) + .compare(penalized, notPenalized); + assertEquals(1, result); + } } From 7dc0edd1430deb8172fb758e6c183a795e394824 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 16 Jan 2024 23:54:28 +0000 Subject: [PATCH 0403/1057] VCN: Adopt the API name changes of IpSecTransformState Update VCN to adopt the API changes that include: - getIpSecTransformState -> requestIpSecTransformState - getTimestamp -> getTimestampMillis Bug: 316603231 Test: atest FrameworksVcnTests; atest CtsVcnTestCases Change-Id: I2498154c37ec2d8f8906a10cb3392326123619e8 --- .../server/vcn/routeselection/IpSecPacketLossDetector.java | 5 +++-- .../server/vcn/routeselection/NetworkMetricMonitor.java | 4 ++-- .../vcn/routeselection/IpSecPacketLossDetectorTest.java | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 5f4852f777..a25d67ab66 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -252,7 +252,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { } getInboundTransformInternal() - .getIpSecTransformState( + .requestIpSecTransformState( new HandlerExecutor(mHandler), new IpSecTransformStateReceiver()); // Schedule for next poll @@ -302,7 +302,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { "packetLossRate: " + packetLossRate + "% in the past " - + (state.getTimestamp() - mLastIpSecTransformState.getTimestamp()) + + (state.getTimestampMillis() + - mLastIpSecTransformState.getTimestampMillis()) + "ms"; mLastIpSecTransformState = state; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index a79f188713..1704aa117a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -138,10 +138,10 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { } /** Poll an IpSecTransformState */ - public void getIpSecTransformState( + public void requestIpSecTransformState( @NonNull Executor executor, @NonNull OutcomeReceiver callback) { - ipSecTransform.getIpSecTransformState(executor, callback); + ipSecTransform.requestIpSecTransformState(executor, callback); } /** Close this instance and release the underlying resources */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 9daba6a79a..1d7be2f4f0 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -144,7 +144,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { mTestLooper.dispatchAll(); verify(mIpSecTransform) - .getIpSecTransformState(any(), mTransformStateReceiverCaptor.capture()); + .requestIpSecTransformState(any(), mTransformStateReceiverCaptor.capture()); return mTransformStateReceiverCaptor.getValue(); } @@ -210,7 +210,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { assertNull(mIpSecPacketLossDetector.getLastTransformState()); mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); mTestLooper.dispatchAll(); - verify(newTransform).getIpSecTransformState(any(), any()); + verify(newTransform).requestIpSecTransformState(any(), any()); } @Test From a564eb57ac5b02c821637fdc3c3844fd367d3aa2 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Mon, 22 Jan 2024 16:09:31 +0900 Subject: [PATCH 0404/1057] Remove aconfig flags for Connectivity FlaggedAPI annotations Split flags.aconfig to platform flags and module flags. Platform flags are used from platform code. Module flags are used for FlaggedAPI annotations in modules. Bug: 321624552 Test: TH Merged-In: Ie8e0f911d0f7d7e81d108b8e8ab539b29a255ad0 Change-Id: Ic868b70b3be10d4e394f005cd55a858acc7ba14d --- Vcn/service-b/src/com/android/server/vcn/VcnContext.java | 4 ++-- .../server/vcn/routeselection/NetworkEvaluationTestBase.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index ed04e5fde0..1383708d8a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -34,7 +34,7 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; - @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -49,7 +49,7 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); - mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl(); + mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl(); } @NonNull diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 6015e93184..381c574968 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -101,7 +101,7 @@ public abstract class NetworkEvaluationTestBase { @Mock protected Context mContext; @Mock protected Network mNetwork; @Mock protected FeatureFlags mFeatureFlags; - @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected TelephonyManager mTelephonyManager; @Mock protected IPowerManager mPowerManagerService; From 130a3613a1a97409c61ba321ed2a9743b2405b2c Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 23 Jan 2024 15:04:18 +0900 Subject: [PATCH 0405/1057] Remove aconfig flags for Connectivity FlaggedAPI annotations Split flags.aconfig to platform flags and module flags. Platform flags are used from platform code. Module flags are used for FlaggedAPI annotations in modules. Bug: 321624552 Test: TH Change-Id: Ie8e0f911d0f7d7e81d108b8e8ab539b29a255ad0 --- Vcn/service-b/src/com/android/server/vcn/VcnContext.java | 4 ++-- .../server/vcn/routeselection/NetworkEvaluationTestBase.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index ed04e5fde0..1383708d8a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -34,7 +34,7 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; - @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -49,7 +49,7 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); - mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl(); + mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl(); } @NonNull diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 6015e93184..381c574968 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -101,7 +101,7 @@ public abstract class NetworkEvaluationTestBase { @Mock protected Context mContext; @Mock protected Network mNetwork; @Mock protected FeatureFlags mFeatureFlags; - @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected TelephonyManager mTelephonyManager; @Mock protected IPowerManager mPowerManagerService; From 20c80b57ac6cef7a13e4e05fd864b9534dd8b8d8 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 23 Jan 2024 15:04:18 +0900 Subject: [PATCH 0406/1057] Remove aconfig flags for Connectivity FlaggedAPI annotations Split flags.aconfig to platform flags and module flags. Platform flags are used from platform code. Module flags are used for FlaggedAPI annotations in modules. This CL cherry-pick ag/25977118 to aosp-main-future. After this CL, aosp/2919289 can be merged. Bug: 321624552 Test: TH Change-Id: Ie8e0f911d0f7d7e81d108b8e8ab539b29a255ad0 Merged-In: Ie8e0f911d0f7d7e81d108b8e8ab539b29a255ad0 --- Vcn/service-b/src/com/android/server/vcn/VcnContext.java | 4 ++-- .../server/vcn/routeselection/NetworkEvaluationTestBase.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index ed04e5fde0..1383708d8a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -34,7 +34,7 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; - @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -49,7 +49,7 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); - mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl(); + mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl(); } @NonNull diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 6015e93184..381c574968 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -101,7 +101,7 @@ public abstract class NetworkEvaluationTestBase { @Mock protected Context mContext; @Mock protected Network mNetwork; @Mock protected FeatureFlags mFeatureFlags; - @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected TelephonyManager mTelephonyManager; @Mock protected IPowerManager mPowerManagerService; From 2d46105d9f90e21428ff091a8afd68a99c6b7aa9 Mon Sep 17 00:00:00 2001 From: Aditya Choudhary Date: Mon, 5 Feb 2024 15:42:14 +0000 Subject: [PATCH 0407/1057] [DON'T BLOCK] Test ownership migration rules This CL is created as a best effort to migrate test targets to the new android ownership model. If you find incorrect or unnecessary attribution in this CL, please create a separate CL to fix that. For more details please refer to the link below, go/new-android-ownership-model Bug: 304529413 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a57eaf06111285ca7f01590e67ad7458d1fe6e2c) Merged-In: I13ce828fdda44c5bcad9ccab8a849b714c0bef08 Change-Id: I13ce828fdda44c5bcad9ccab8a849b714c0bef08 --- Vcn/tests/cts/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 59f15f0f6a..c9cd31d107 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_enigma", default_applicable_licenses: ["Android-Apache-2.0"], } From 0259b81f54a1ada4ab73969d2c864473173f4ccc Mon Sep 17 00:00:00 2001 From: Aditya Choudhary Date: Mon, 5 Feb 2024 15:42:14 +0000 Subject: [PATCH 0408/1057] [DON'T BLOCK] Test ownership migration rules This CL is created as a best effort to migrate test targets to the new android ownership model. If you find incorrect or unnecessary attribution in this CL, please create a separate CL to fix that. For more details please refer to the link below, go/new-android-ownership-model Ignore-AOSP-First: cherry picked from aosp/2951185 Bug: 304529413 Test: N/A Change-Id: I13ce828fdda44c5bcad9ccab8a849b714c0bef08 --- Vcn/tests/cts/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 59f15f0f6a..c9cd31d107 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_enigma", default_applicable_licenses: ["Android-Apache-2.0"], } From 3ec125b7c54bf79692728fcda4baf743d870f42f Mon Sep 17 00:00:00 2001 From: Aditya Choudhary Date: Mon, 5 Feb 2024 15:42:14 +0000 Subject: [PATCH 0409/1057] [DON'T BLOCK] Test ownership migration rules This CL is created as a best effort to migrate test targets to the new android ownership model. If you find incorrect or unnecessary attribution in this CL, please create a separate CL to fix that. For more details please refer to the link below, go/new-android-ownership-model Bug: 304529413 Test: N/A Change-Id: I13ce828fdda44c5bcad9ccab8a849b714c0bef08 Merged-In: I13ce828fdda44c5bcad9ccab8a849b714c0bef08 --- Vcn/tests/cts/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 59f15f0f6a..c9cd31d107 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_enigma", default_applicable_licenses: ["Android-Apache-2.0"], } From f47e3f2ec1dc0b108de4f575760dd01df2fc230e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 15 Feb 2024 00:24:55 +0000 Subject: [PATCH 0410/1057] Migrate VCN UT to New Android Ownership Model CL created based on go/new-android-ownership-model Bug: 304529413 Test: make Change-Id: I7db3a93e8f4752591822062e043ee7126248b2cc --- Vcn/tests/unit/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 228520e854..bc1df75bb1 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -3,6 +3,7 @@ //######################################################################## package { + default_team: "trendy_team_enigma", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_base_license" From ee3f52163f38d541e089b379ac50405fc07da672 Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 21 Feb 2024 10:13:40 -0600 Subject: [PATCH 0411/1057] Fix VCN crash when retrieving carrier config while phone is gone This CL calls CarrierConfigManager.getCarrierConfigSubset instead of getConfigForSubId to guard against crashing when phone process has gone. The former method is designed for system components to retrieve carrier configs with consideration of phone process may be gone (e.g. during rebooting from previous crash). Bug: 319791612 Test: atest TelephonySubscriptionTrackerTest Change-Id: I784610b243db2a666c1fe89b1438950a2f6a1478 --- .../vcn/TelephonySubscriptionTracker.java | 9 +++++++-- Vcn/tests/unit/Android.bp | 1 + .../vcn/TelephonySubscriptionTrackerTest.java | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 099c9ae33b..17f5e9585c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -44,6 +44,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.telephony.flags.Flags; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; @@ -318,8 +319,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { if (SubscriptionManager.isValidSubscriptionId(subId)) { // Get only configs as needed to save memory. - final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId, - VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); + final PersistableBundle carrierConfig = + Flags.fixCrashOnGettingConfigWhenPhoneIsGone() + ? CarrierConfigManager.getCarrierConfigSubset(mContext, subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS) + : mCarrierConfigManager.getConfigForSubId(subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) { mReadySubIdsBySlotId.put(slotId, subId); diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index 228520e854..308889f34d 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -30,6 +30,7 @@ android_test { "platform-test-annotations", "services.core", "service-connectivity-tiramisu-pre-jarjar", + "flag-junit", ], libs: [ "android.test.runner", diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 34f884b942..887630b03a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -38,6 +38,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; @@ -58,6 +59,7 @@ import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -71,7 +73,10 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.telephony.flags.Flags; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -128,6 +133,9 @@ public class TelephonySubscriptionTrackerTest { TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap); } + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; @NonNull private final Handler mHandler; @@ -185,6 +193,7 @@ public class TelephonySubscriptionTrackerTest { @Before public void setUp() throws Exception { + mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CRASH_ON_GETTING_CONFIG_WHEN_PHONE_IS_GONE); doReturn(2).when(mTelephonyManager).getActiveModemCount(); mCallback = mock(TelephonySubscriptionTrackerCallback.class); @@ -594,4 +603,14 @@ public class TelephonySubscriptionTrackerTest { new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID)); } + + @Test + public void testCarrierConfigChangeWhenPhoneIsGoneShouldNotCrash() throws Exception { + doThrow(new IllegalStateException("Carrier config loader is not available.")) + .when(mCarrierConfigManager) + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); + + sendCarrierConfigChange(true /* hasValidSubscription */); + mTestLooper.dispatchAll(); + } } From 02d4ac2ca8cbf31ff9b277f7159519dcc28aeb54 Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Fri, 23 Feb 2024 16:30:43 +0000 Subject: [PATCH 0412/1057] Remove redundant TODO comment in TelephonySubscriptionTracker The CL simply removes the redundant TODO comment because the planned work has been delivered. Bug: 221306368 Test: make Flag: EXEMPT Change-Id: I42c5affd2635876402565465048fc65908c9d88b --- .../src/com/android/server/vcn/TelephonySubscriptionTracker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 17f5e9585c..7206c0377b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -164,7 +164,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { registerCarrierPrivilegesCallbacks(); } - // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback private void registerCarrierPrivilegesCallbacks() { final HandlerExecutor executor = new HandlerExecutor(mHandler); final int modemCount = mTelephonyManager.getActiveModemCount(); From 19e2df49e78d1fcfa5badd7fbf7a1c18582d6cf8 Mon Sep 17 00:00:00 2001 From: Oriol Prieto Gasco Date: Fri, 1 Mar 2024 17:12:01 +0000 Subject: [PATCH 0413/1057] Export flags used in FlaggedApi annotations Before calling a flagged API, client code must check the value of the flag which gates it. Those flags must be exported in order to be accessible from containers other than the container where the flag and the API are hosted. Bug: 320984775 Bug: 322839671 Test: m all_aconfig_declarations Test: printflags --format='{fully_qualified_name}:{is_exported}' | grep true Change-Id: Ie5af316c327208b52b3afd74502ca66c41bb6f70 --- Vcn/flags/flags.aconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 7afd72195f..97b773ee12 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -2,6 +2,7 @@ package: "android.net.vcn" flag { name: "safe_mode_config" + is_exported: true namespace: "vcn" description: "Feature flag for safe mode configurability" bug: "276358140" From 40ef762340b07a6386b8fafac43c91abe9f8f768 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 7 Mar 2024 14:57:15 -0800 Subject: [PATCH 0414/1057] Fix crash on potentially missing CarrierConfigManager [TelephonySubscriptionTracker] Bug: 310710841 Test: it builds and boots Change-Id: I69b38d464f57dd8f102b9294befea622d119d344 --- .../server/vcn/TelephonySubscriptionTracker.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 7206c0377b..ecd140e23a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -89,7 +89,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final TelephonyManager mTelephonyManager; @NonNull private final SubscriptionManager mSubscriptionManager; - @NonNull private final CarrierConfigManager mCarrierConfigManager; + @Nullable private final CarrierConfigManager mCarrierConfigManager; @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener; @@ -158,8 +158,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); - mCarrierConfigManager.registerCarrierConfigChangeListener(executor, - mCarrierConfigChangeListener); + if (mCarrierConfigManager != null) { + mCarrierConfigManager.registerCarrierConfigChangeListener(executor, + mCarrierConfigChangeListener); + } registerCarrierPrivilegesCallbacks(); } @@ -200,7 +202,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); - mCarrierConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); + if (mCarrierConfigManager != null) { + mCarrierConfigManager.unregisterCarrierConfigChangeListener( + mCarrierConfigChangeListener); + } unregisterCarrierPrivilegesCallbacks(); } From 47049a35729b51b87781d9d75bf51b49b81e4009 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 29 Feb 2024 02:08:38 +0000 Subject: [PATCH 0415/1057] CTS for configuring VCN safe mode Add CTS tests that verify disabling safe mode and configuring safe mode timeout. Support verifying safe mode with VcnStatusCallback Bug: 308000143 Bug: 191801185 Test: adb shell device_config vcn android.net.vcn.safe_mode_timeout_config true && adb shell device_config vcn android.net.vcn.safe_mode_config true && atest CtsVcnTestCases:VcnManagerTest (new tests) Change-Id: I526b00134f58c5c8c334c9dfc9cb5aa7f30631f6 --- Vcn/tests/cts/Android.bp | 2 + .../cts/VcnGatewayConnectionConfigTest.java | 23 +++ .../android/net/vcn/cts/VcnManagerTest.java | 152 ++++++++++++++++-- 3 files changed, 162 insertions(+), 15 deletions(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index c9cd31d107..ca9c3a99b8 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -40,6 +40,8 @@ android_test { "ike-tun-utils", "net-tests-utils", "telephony-cts-utils", + "android.net.vcn.flags-aconfig-java", + "flag-junit", ], platform_apis: true, diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index b48be30571..99d0c2ef47 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -29,11 +29,16 @@ import static org.junit.Assert.fail; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.vcn.Flags; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,6 +50,9 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnGatewayConnectionConfigTest extends VcnTestBase { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; private static final long[] RETRY_INTERNAL_MILLIS = new long[] { @@ -182,4 +190,19 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { } catch (IllegalArgumentException e) { } } + + @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) + @Test + public void testBuilderSetSafeModeEnabled() { + final VcnGatewayConnectionConfig gatewayConnConfig = + buildVcnGatewayConnectionConfigBase().setSafeModeEnabled(false).build(); + assertFalse(gatewayConnConfig.isSafeModeEnabled()); + } + + @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) + @Test + public void testGetSafeModeEnabledDefault() { + final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfig(); + assertTrue(gatewayConnConfig.isSafeModeEnabled()); + } } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index e1a2022b19..08709f6e0d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -28,6 +28,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; @@ -58,8 +61,10 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.vcn.Flags; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnNetworkPolicyResult; import android.net.vcn.VcnUnderlyingNetworkTemplate; @@ -69,6 +74,10 @@ import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.Capabilitie import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.SystemClock; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.cts.util.SubscriptionGroupUtils; @@ -80,6 +89,7 @@ import com.android.compatibility.common.util.CarrierPrivilegeUtils; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -90,12 +100,17 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnManagerTest extends VcnTestBase { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; @@ -105,6 +120,8 @@ public class VcnManagerTest extends VcnTestBase { private static final int TEST_NETWORK_MTU = 1500; + private static final int VCN_STATUS_CODE_AWAIT_TIMEOUT = -1; + private static final InetAddress LOCAL_ADDRESS = InetAddresses.parseNumericAddress("198.51.100.1"); private static final InetAddress SECONDARY_LOCAL_ADDRESS = @@ -118,6 +135,7 @@ public class VcnManagerTest extends VcnTestBase { private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private final CarrierConfigManager mCarrierConfigManager; public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); @@ -125,6 +143,7 @@ public class VcnManagerTest extends VcnTestBase { mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); } @Before @@ -460,32 +479,43 @@ public class VcnManagerTest extends VcnTestBase { /** Test implementation of VcnStatusCallback for verification purposes. */ private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback { - private final CompletableFuture mFutureOnStatusChanged = - new CompletableFuture<>(); - private final CompletableFuture mFutureOnGatewayConnectionError = - new CompletableFuture<>(); + private final BlockingQueue mOnStatusChangedHistory = new LinkedBlockingQueue<>(); + private final BlockingQueue mOnGatewayConnectionErrorHistory = + new LinkedBlockingQueue<>(); @Override public void onStatusChanged(int statusCode) { - mFutureOnStatusChanged.complete(statusCode); + mOnStatusChangedHistory.offer(statusCode); } @Override public void onGatewayConnectionError( @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) { - mFutureOnGatewayConnectionError.complete( + mOnGatewayConnectionErrorHistory.offer( new GatewayConnectionError(gatewayConnectionName, errorCode, detail)); } public int awaitOnStatusChanged() throws Exception { - return mFutureOnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + final Integer status = mOnStatusChangedHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); + + // Null means timeout + return status == null ? VCN_STATUS_CODE_AWAIT_TIMEOUT : status; } public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception { - return mFutureOnGatewayConnectionError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + return mOnGatewayConnectionErrorHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); } } + private void verifyVcnStatus(ParcelUuid subGrp, int expectedStatus) throws Exception { + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback); + + assertEquals(expectedStatus, callback.awaitOnStatusChanged()); + + mVcnManager.unregisterVcnStatusCallback(callback); + } + /** Info class for organizing VcnStatusCallback#onGatewayConnectionError response data. */ private static class GatewayConnectionError { @NonNull public final String gatewayConnectionName; @@ -1225,10 +1255,8 @@ public class VcnManagerTest extends VcnTestBase { true /* expectedUseEncap */); } - @Test - public void testVcnSafemodeOnTestNetwork() throws Exception { - final int subId = verifyAndGetValidDataSubId(); - + private void verifyVcnSafeModeTimeoutOnTestNetwork(int subId, long timeoutMillis) + throws Exception { try (TestNetworkWrapper testNetworkWrapper = createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { // Before the VCN starts, the test network should have NOT_VCN_MANAGED @@ -1241,8 +1269,6 @@ public class VcnManagerTest extends VcnTestBase { final VcnSetupResult vcnSetupResult = setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); - // TODO(b/191801185): use VcnStatusCallbacks to verify safemode - // Once VCN starts, the test network should lose NOT_VCN_MANAGED waitForExpectedUnderlyingNetworkWithCapabilities( testNetworkWrapper, @@ -1256,14 +1282,110 @@ public class VcnManagerTest extends VcnTestBase { testNetworkWrapper, true /* expectNotVcnManaged */, false /* expectNotMetered */, - SAFEMODE_TIMEOUT_MILLIS); + timeoutMillis); // Verify that VCN Network is also lost in safemode final Network lostVcnNetwork = cellNetworkCb.waitForLost(); assertEquals(vcnSetupResult.vcnNetwork, lostVcnNetwork); + verifyVcnStatus(subGrp, VCN_STATUS_CODE_SAFE_MODE); + mVcnManager.clearVcnConfig(subGrp); }); } } + + private void setSafeModeTimeoutForCarrier(int subId, int timeoutSeconds) { + final PersistableBundle carrierConfig = new PersistableBundle(); + carrierConfig.putInt(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, timeoutSeconds); + mCarrierConfigManager.overrideConfig(subId, carrierConfig); + } + + @Test + public void testVcnSafeModeOnTestNetwork_defaultTimeout() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + verifyVcnSafeModeTimeoutOnTestNetwork(subId, SAFEMODE_TIMEOUT_MILLIS); + } + + @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG) + @Test + public void testVcnSafeModeOnTestNetwork_overrideTimeout() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final int safeModeTimeoutSeconds = 5; + final int gracePeriod = 5; + + final PersistableBundle oldCarrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + setSafeModeTimeoutForCarrier(subId, safeModeTimeoutSeconds); + + verifyVcnSafeModeTimeoutOnTestNetwork( + subId, TimeUnit.SECONDS.toMillis(safeModeTimeoutSeconds + gracePeriod)); + + mCarrierConfigManager.overrideConfig(subId, oldCarrierConfig); + } + + private void verifyEnterSafeModeImmediately(VcnConfig vcnConfig, boolean isSafeModeExpected) + throws Exception { + final int subId = verifyAndGetValidDataSubId(); + final TestVcnStatusCallback callback = new TestVcnStatusCallback(); + + // Override the safe mode timeout to be zero + final PersistableBundle oldCarrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + setSafeModeTimeoutForCarrier(subId, 0); + + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + mVcnManager.registerVcnStatusCallback(subGrp, INLINE_EXECUTOR, callback); + mVcnManager.setVcnConfig(subGrp, vcnConfig); + + assertEquals( + VCN_STATUS_CODE_NOT_CONFIGURED, callback.awaitOnStatusChanged()); + assertEquals(VCN_STATUS_CODE_ACTIVE, callback.awaitOnStatusChanged()); + + if (isSafeModeExpected) { + assertEquals( + VCN_STATUS_CODE_SAFE_MODE, callback.awaitOnStatusChanged()); + } else { + assertEquals( + VCN_STATUS_CODE_AWAIT_TIMEOUT, callback.awaitOnStatusChanged()); + } + + mVcnManager.clearVcnConfig(subGrp); + mVcnManager.unregisterVcnStatusCallback(callback); + }); + } + + // Reset Carrier Config + mCarrierConfigManager.overrideConfig(subId, oldCarrierConfig); + } + + private VcnConfig newVcnConfig(boolean isSafeModeEnabled) { + final VcnGatewayConnectionConfig.Builder gatewayConfigBuilder = + VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfigBase() + .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_MMS); + + if (!isSafeModeEnabled) { + gatewayConfigBuilder.setSafeModeEnabled(false); + } + // Don't call setSafeModeEnabled since enabling safe mode should not be flag gated + + return new VcnConfig.Builder(mContext) + .setIsTestModeProfile() + .addGatewayConnectionConfig(gatewayConfigBuilder.build()) + .build(); + } + + @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) + @Test + public void testEnterSafeModeImmediately_safeModeEnabled() throws Exception { + verifyEnterSafeModeImmediately( + newVcnConfig(true /* isSafeModeEnabled */), true /* isSafeModeExpected */); + } + + @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_CONFIG, Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) + @Test + public void testEnterSafeModeImmediately_safeModeDisabled() throws Exception { + verifyEnterSafeModeImmediately( + newVcnConfig(false /* isSafeModeEnabled */), false /* isSafeModeExpected */); + } } From bb5fd85fd9bcebb7a767230c5ad03bb64195bc1b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 19 Mar 2024 23:07:22 +0000 Subject: [PATCH 0416/1057] Add @RequiresFeature for VcnManager Add @RequiresFeature to align with the implementation that makes VCN availability depent on FEATURE_TELEPHONY_SUBSCRIPTION Bug: 330404031 Test: build Change-Id: I3e35f3d21014edbfca29fd2abd99d05531916f49 --- Vcn/framework-b/src/android/net/vcn/VcnManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 83b7edaec7..6246dd77fd 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -20,10 +20,12 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.content.pm.PackageManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.os.Binder; @@ -69,8 +71,13 @@ import java.util.concurrent.Executor; * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default. * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will * automatically exit Safe Mode if all active tunnels connect successfully. + * + *

    Apps targeting Android 15 or newer should check the existence of {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} before querying the service. If the feature is + * absent, {@link Context#getSystemService} may return null. */ @SystemService(Context.VCN_MANAGEMENT_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); From c81d89f71f81321b2e6435e7314408ebdb0202c7 Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 20 Mar 2024 18:41:14 +0000 Subject: [PATCH 0417/1057] Fix VCN crash when retrieving carrier config while phone is gone This CL calls CarrierConfigManager.getCarrierConfigSubset instead of getConfigForSubId to guard against crashing when phone process has gone. The former method is designed for system components to retrieve carrier configs with consideration of phone process may be gone (e.g. during rebooting from previous crash). Bug: 319791612 Test: atest TelephonySubscriptionTrackerTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ee3f52163f38d541e089b379ac50405fc07da672) Merged-In: I784610b243db2a666c1fe89b1438950a2f6a1478 Change-Id: I784610b243db2a666c1fe89b1438950a2f6a1478 --- .../vcn/TelephonySubscriptionTracker.java | 9 +++++++-- Vcn/tests/unit/Android.bp | 1 + .../vcn/TelephonySubscriptionTrackerTest.java | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 099c9ae33b..17f5e9585c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -44,6 +44,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.telephony.flags.Flags; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; @@ -318,8 +319,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { if (SubscriptionManager.isValidSubscriptionId(subId)) { // Get only configs as needed to save memory. - final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId, - VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); + final PersistableBundle carrierConfig = + Flags.fixCrashOnGettingConfigWhenPhoneIsGone() + ? CarrierConfigManager.getCarrierConfigSubset(mContext, subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS) + : mCarrierConfigManager.getConfigForSubId(subId, + VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS); if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) { mReadySubIdsBySlotId.put(slotId, subId); diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index bc1df75bb1..ee2e7cfcd4 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -31,6 +31,7 @@ android_test { "platform-test-annotations", "services.core", "service-connectivity-tiramisu-pre-jarjar", + "flag-junit", ], libs: [ "android.test.runner", diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 34f884b942..887630b03a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -38,6 +38,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; @@ -58,6 +59,7 @@ import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -71,7 +73,10 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.telephony.flags.Flags; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -128,6 +133,9 @@ public class TelephonySubscriptionTrackerTest { TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap); } + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @NonNull private final Context mContext; @NonNull private final TestLooper mTestLooper; @NonNull private final Handler mHandler; @@ -185,6 +193,7 @@ public class TelephonySubscriptionTrackerTest { @Before public void setUp() throws Exception { + mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CRASH_ON_GETTING_CONFIG_WHEN_PHONE_IS_GONE); doReturn(2).when(mTelephonyManager).getActiveModemCount(); mCallback = mock(TelephonySubscriptionTrackerCallback.class); @@ -594,4 +603,14 @@ public class TelephonySubscriptionTrackerTest { new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID)); } + + @Test + public void testCarrierConfigChangeWhenPhoneIsGoneShouldNotCrash() throws Exception { + doThrow(new IllegalStateException("Carrier config loader is not available.")) + .when(mCarrierConfigManager) + .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any()); + + sendCarrierConfigChange(true /* hasValidSubscription */); + mTestLooper.dispatchAll(); + } } From 97a248154ba5422cfbe99807587bf5c08fc1c3e8 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 20 Mar 2024 02:49:06 +0000 Subject: [PATCH 0418/1057] Add flags for IPsec packet loss detector improvements Bug: 329139898 Bug: 323238888 Test: build Change-Id: I635e5432e42c5fb4d903b4c14910e60e2e38f12b --- Vcn/flags/flags.aconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 97b773ee12..e64823af84 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -20,4 +20,18 @@ flag{ namespace: "vcn" description: "Feature flag for enabling network metric monitor" bug: "282996138" +} + +flag{ + name: "validate_network_on_ipsec_loss" + namespace: "vcn" + description: "Trigger network validation when IPsec packet loss exceeds the threshold" + bug: "329139898" +} + +flag{ + name: "evaluate_ipsec_loss_on_lp_nc_change" + namespace: "vcn" + description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change" + bug: "323238888" } \ No newline at end of file From 4e057c24f0fe41bed2adc38cfbb0a6bbf5c54256 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 20 Mar 2024 18:04:46 +0000 Subject: [PATCH 0419/1057] Re-evaluate network when IPsec loss exceeds the threshold Bug: 329139898 Test: atest IpSecPacketLossDetectorTest (new tests) Change-Id: Icc31fe7f1b76e7849c910b3cd1c300bcf4c1f3a3 --- .../routeselection/IpSecPacketLossDetector.java | 12 ++++++++++++ .../vcn/routeselection/NetworkMetricMonitor.java | 5 +++++ .../IpSecPacketLossDetectorTest.java | 1 + .../routeselection/NetworkEvaluationTestBase.java | 15 +++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index a25d67ab66..f3d7dd19ec 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -24,8 +24,10 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; import android.net.IpSecTransformState; import android.net.Network; +import android.net.vcn.Flags; import android.net.vcn.VcnManager; import android.os.Handler; import android.os.HandlerExecutor; @@ -71,6 +73,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { @NonNull private final Handler mHandler; @NonNull private final PowerManager mPowerManager; + @NonNull private final ConnectivityManager mConnectivityManager; @NonNull private final Object mCancellationToken = new Object(); @NonNull private final PacketLossCalculator mPacketLossCalculator; @@ -98,6 +101,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mHandler = new Handler(getVcnContext().getLooper()); mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class); + mConnectivityManager = + getVcnContext().getContext().getSystemService(ConnectivityManager.class); mPacketLossCalculator = deps.getPacketLossCalculator(); @@ -313,6 +318,13 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { } else { logInfo(logMsg); onValidationResultReceivedInternal(true /* isFailed */); + + if (Flags.validateNetworkOnIpsecLoss()) { + // Trigger re-validation of the underlying network; if it fails, the VCN will + // attempt to migrate away. + mConnectivityManager.reportNetworkConnectivity( + getNetwork(), false /* hasConnectivity */); + } } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 1704aa117a..4bacf3b8ab 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -203,6 +203,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { return mVcnContext; } + @NonNull + public Network getNetwork() { + return mNetwork; + } + // Override methods for AutoCloseable. Subclasses MUST call super when overriding this method @Override public void close() { diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 1d7be2f4f0..5107943c35 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -333,6 +333,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { public void testHandleLossRate_validationFail() throws Exception { checkHandleLossRate( 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false); } @Test diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 381c574968..444208edc4 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.ConnectivityManager; import android.net.IpSecConfig; import android.net.IpSecTransform; import android.net.LinkProperties; @@ -33,12 +34,14 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.FeatureFlags; +import android.net.vcn.Flags; import android.os.Handler; import android.os.IPowerManager; import android.os.IThermalService; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.TelephonyManager; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -46,6 +49,7 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import org.junit.Before; +import org.junit.Rule; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -53,6 +57,8 @@ import java.util.Set; import java.util.UUID; public abstract class NetworkEvaluationTestBase { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + protected static final String SSID = "TestWifi"; protected static final String SSID_OTHER = "TestWifiOther"; protected static final String PLMN_ID = "123456"; @@ -103,6 +109,7 @@ public abstract class NetworkEvaluationTestBase { @Mock protected FeatureFlags mFeatureFlags; @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; + @Mock protected ConnectivityManager mConnectivityManager; @Mock protected TelephonyManager mTelephonyManager; @Mock protected IPowerManager mPowerManagerService; @@ -114,6 +121,8 @@ public abstract class NetworkEvaluationTestBase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); + when(mNetwork.getNetId()).thenReturn(-1); mTestLooper = new TestLooper(); @@ -129,6 +138,12 @@ public abstract class NetworkEvaluationTestBase { doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); + setupSystemService( + mContext, + mConnectivityManager, + Context.CONNECTIVITY_SERVICE, + ConnectivityManager.class); + setupSystemService( mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); From 2434557b2a3883689730da31cc0bc4a0d2366011 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 20 Mar 2024 22:27:08 +0000 Subject: [PATCH 0420/1057] Re-evaluate IPsec packet loss on LP/NC change Bug: 323238888 Test: atest FrameworksVcnTests(new tests) Change-Id: I83f2da42fe0ffed5d4403429e968510c7eeabec1 --- .../IpSecPacketLossDetector.java | 12 +++++++ .../routeselection/NetworkMetricMonitor.java | 5 +++ .../UnderlyingNetworkEvaluator.java | 13 ++++++++ .../IpSecPacketLossDetectorTest.java | 28 ++++++++++++++++ .../NetworkEvaluationTestBase.java | 1 + .../UnderlyingNetworkEvaluatorTest.java | 33 +++++++++++++++++++ 6 files changed, 92 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index f3d7dd19ec..ed9fa65dee 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -209,6 +209,18 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); } + @Override + public void onLinkPropertiesOrCapabilitiesChanged() { + if (!isStarted()) return; + + reschedulePolling(); + } + + private void reschedulePolling() { + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L); + } + @Override protected void start() { super.start(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 4bacf3b8ab..a1b212f8d3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -186,6 +186,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { // Subclasses MUST override it if they care } + /** Called when LinkProperties or NetworkCapabilities have changed */ + public void onLinkPropertiesOrCapabilitiesChanged() { + // Subclasses MUST override it if they care + } + public boolean isValidationFailed() { return mIsValidationFailed; } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 2f4cf5e5d8..78e06d46c7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -25,6 +25,7 @@ import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.vcn.Flags; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; @@ -295,6 +296,12 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + if (Flags.evaluateIpsecLossOnLpNcChange()) { + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.onLinkPropertiesOrCapabilitiesChanged(); + } + } } /** Set the LinkProperties */ @@ -308,6 +315,12 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + if (Flags.evaluateIpsecLossOnLpNcChange()) { + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.onLinkPropertiesOrCapabilitiesChanged(); + } + } } /** Set whether the network is blocked */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 5107943c35..fdf8fb8d3c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -417,4 +418,31 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { checkGetPacketLossRate(oldState, 20000, 14000, 4096, 19); checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10); } + + // Verify the polling event is scheduled with expected delays + private void verifyPollEventDelayAndScheduleNext(long expectedDelayMs) { + if (expectedDelayMs > 0) { + mTestLooper.dispatchAll(); + verify(mIpSecTransform, never()).requestIpSecTransformState(any(), any()); + mTestLooper.moveTimeForward(expectedDelayMs); + } + + mTestLooper.dispatchAll(); + verify(mIpSecTransform).requestIpSecTransformState(any(), any()); + reset(mIpSecTransform); + } + + @Test + public void testOnLinkPropertiesOrCapabilitiesChange() throws Exception { + // Start the monitor; verify the 1st poll is scheduled without delay + startMonitorAndCaptureStateReceiver(); + verifyPollEventDelayAndScheduleNext(0 /* expectedDelayMs */); + + // Verify the 2nd poll is rescheduled without delay + mIpSecPacketLossDetector.onLinkPropertiesOrCapabilitiesChanged(); + verifyPollEventDelayAndScheduleNext(0 /* expectedDelayMs */); + + // Verify the 3rd poll is scheduled with configured delay + verifyPollEventDelayAndScheduleNext(POLL_IPSEC_STATE_INTERVAL_MS); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 444208edc4..af6daa17e2 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -122,6 +122,7 @@ public abstract class NetworkEvaluationTestBase { MockitoAnnotations.initMocks(this); mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); + mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); when(mNetwork.getNetId()).thenReturn(-1); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java index aa81efe9a1..1d6872195e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.eq; 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.when; @@ -333,4 +334,36 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { .compare(penalized, notPenalized); assertEquals(1, result); } + + @Test + public void testNotifyNetworkMetricMonitorOnLpChange() throws Exception { + // Clear calls invoked when initializing mNetworkEvaluator + reset(mIpSecPacketLossDetector); + + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + evaluator.setNetworkCapabilities( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + verify(mIpSecPacketLossDetector).onLinkPropertiesOrCapabilitiesChanged(); + } + + @Test + public void testNotifyNetworkMetricMonitorOnNcChange() throws Exception { + // Clear calls invoked when initializing mNetworkEvaluator + reset(mIpSecPacketLossDetector); + + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + evaluator.setLinkProperties( + LINK_PROPERTIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + verify(mIpSecPacketLossDetector).onLinkPropertiesOrCapabilitiesChanged(); + } } From 2af45e16b7514094f91e83a12dab83e96654aba2 Mon Sep 17 00:00:00 2001 From: Yu Liu Date: Fri, 29 Mar 2024 23:33:20 +0000 Subject: [PATCH 0421/1057] Set container to system for aconfig_declarations in AconfigFlags.bp Bug: 330354107 Test: CI Flag: NONE Ignore-AOSP-First: It is easier to detect all the mismatch in internal master. Change-Id: I41c11c7deda2936d39701a3a694166c5e49d423a --- Vcn/flags/flags.aconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index e64823af84..15d671dde0 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -1,4 +1,5 @@ package: "android.net.vcn" +container: "system" flag { name: "safe_mode_config" From dc53a8b0beb02e4a434f6d898fd2d8e2ed0c1e1b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 1 Apr 2024 19:08:17 +0000 Subject: [PATCH 0422/1057] Ensure Internet probing won't be skipped on VCN Tests This patch fixes safe mode tests by ensuring VCN will enter safe mode. Safe mode tests are based on the assumption that VCN networks will never pass network validation. However, in some cases the system skips Internet probing check and reports "valid" because the captive portal mode is overriden to "ignore", causing test failures. This patch always set captive portal mode to "prompt" to ensure that validation will not be skipped. Bug: 331452561 Test: adb shell settings put global captive_portal_mode 0 && atest CtsVcnTestCases:VcnManagerTest Change-Id: I5c31086f5dd677ac32479582defa44e5ade7477e --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index 87525a14a6..b37e174e8a 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -27,6 +27,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 08709f6e0d..9c30d0555f 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -19,6 +19,9 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; +import static android.net.ConnectivitySettingsManager.getCaptivePortalMode; +import static android.net.ConnectivitySettingsManager.setCaptivePortalMode; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; @@ -136,6 +139,7 @@ public class VcnManagerTest extends VcnTestBase { private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; private final CarrierConfigManager mCarrierConfigManager; + private final int mOldCaptivePortalMode; public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); @@ -144,6 +148,8 @@ public class VcnManagerTest extends VcnTestBase { mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + + mOldCaptivePortalMode = getCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @Before @@ -151,10 +157,14 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); + + // Ensure Internet probing check will be performed on VCN networks + setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @After public void tearDown() throws Exception { + setCaptivePortalMode(mContext, mOldCaptivePortalMode); getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } From 56037c0b6829f8e4c7285dbf80b9c225729d0e3d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 1 Apr 2024 19:08:17 +0000 Subject: [PATCH 0423/1057] Ensure Internet probing won't be skipped on VCN Tests This patch fixes safe mode tests by ensuring VCN will enter safe mode. Safe mode tests are based on the assumption that VCN networks will never pass network validation. However, in some cases the system skips Internet probing check and reports "valid" because the captive portal mode is overriden to "ignore", causing test failures. This patch always set captive portal mode to "prompt" to ensure that validation will not be skipped. Bug: 331452561 Test: adb shell settings put global captive_portal_mode 0 && atest CtsVcnTestCases:VcnManagerTest Merged-In: I5c31086f5dd677ac32479582defa44e5ade7477e Change-Id: I5c31086f5dd677ac32479582defa44e5ade7477e --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..3324d9663d 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -27,6 +27,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 70467e3f58..d83d179a0d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -19,6 +19,9 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; +import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; +import static android.net.ConnectivitySettingsManager.getCaptivePortalMode; +import static android.net.ConnectivitySettingsManager.setCaptivePortalMode; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; @@ -118,6 +121,7 @@ public class VcnManagerTest extends VcnTestBase { private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private final int mOldCaptivePortalMode; public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); @@ -125,6 +129,7 @@ public class VcnManagerTest extends VcnTestBase { mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mOldCaptivePortalMode = getCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @Before @@ -132,10 +137,14 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); + + // Ensure Internet probing check will be performed on VCN networks + setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @After public void tearDown() throws Exception { + setCaptivePortalMode(mContext, mOldCaptivePortalMode); getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } From 840912a91a2f85d0ab45cc494867dc9a4cf70752 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 1 Apr 2024 19:08:17 +0000 Subject: [PATCH 0424/1057] Ensure Internet probing won't be skipped on VCN Tests This patch fixes safe mode tests by ensuring VCN will enter safe mode. Safe mode tests are based on the assumption that VCN networks will never pass network validation. However, in some cases the system skips Internet probing check and reports "valid" because the captive portal mode is overriden to "ignore", causing test failures. This patch always set captive portal mode to "prompt" to ensure that validation will not be skipped. Bug: 331452561 Test: adb shell settings put global captive_portal_mode 0 && atest CtsVcnTestCases:VcnManagerTest Merged-In: I5c31086f5dd677ac32479582defa44e5ade7477e Change-Id: I5c31086f5dd677ac32479582defa44e5ade7477e --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..3324d9663d 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -27,6 +27,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 028c6b790b..26d9e6123d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -18,6 +18,9 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; +import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; +import static android.net.ConnectivitySettingsManager.getCaptivePortalMode; +import static android.net.ConnectivitySettingsManager.setCaptivePortalMode; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; @@ -104,6 +107,7 @@ public class VcnManagerTest extends VcnTestBase { private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private final int mOldCaptivePortalMode; public VcnManagerTest() { mContext = InstrumentationRegistry.getContext(); @@ -111,6 +115,7 @@ public class VcnManagerTest extends VcnTestBase { mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mOldCaptivePortalMode = getCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @Before @@ -118,10 +123,14 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); + + // Ensure Internet probing check will be performed on VCN networks + setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @After public void tearDown() throws Exception { + setCaptivePortalMode(mContext, mOldCaptivePortalMode); getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } From 8fbf8b392acd1b73b20a431ed8684e7a356fd240 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 1 Apr 2024 19:08:17 +0000 Subject: [PATCH 0425/1057] Ensure Internet probing won't be skipped on VCN Tests This patch fixes safe mode tests by ensuring VCN will enter safe mode. Safe mode tests are based on the assumption that VCN networks will never pass network validation. However, in some cases the system skips Internet probing check and reports "valid" because the captive portal mode is overriden to "ignore", causing test failures. This patch always set captive portal mode to "prompt" to ensure that validation will not be skipped. Bug: 331452561 Test: adb shell settings put global captive_portal_mode 0 && atest CtsVcnTestCases:VcnManagerTest Merged-In: I5c31086f5dd677ac32479582defa44e5ade7477e Change-Id: I5c31086f5dd677ac32479582defa44e5ade7477e --- Vcn/tests/cts/AndroidManifest.xml | 2 ++ .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index ac0625cc5e..3324d9663d 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -27,6 +27,8 @@ + + diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9670611439..b87fb9b25d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -17,6 +17,9 @@ package android.net.vcn.cts; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; +import static android.net.ConnectivitySettingsManager.getCaptivePortalMode; +import static android.net.ConnectivitySettingsManager.setCaptivePortalMode; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; @@ -95,6 +98,7 @@ public class VcnManagerTest extends VcnTestBase { private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; private final ConnectivityManager mConnectivityManager; + private final int mOldCaptivePortalMode; private TestNetworkWrapper mTestNetworkWrapper; @@ -104,6 +108,7 @@ public class VcnManagerTest extends VcnTestBase { mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mOldCaptivePortalMode = getCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @Before @@ -111,6 +116,9 @@ public class VcnManagerTest extends VcnTestBase { assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); + + // Ensure Internet probing check will be performed on VCN networks + setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); } @After @@ -121,6 +129,7 @@ public class VcnManagerTest extends VcnTestBase { mTestNetworkWrapper = null; } } finally { + setCaptivePortalMode(mContext, mOldCaptivePortalMode); getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); } } From df5d8a5494bacfbb9b67f7f97f3d4762b0f9bdf5 Mon Sep 17 00:00:00 2001 From: Yu Liu Date: Mon, 8 Apr 2024 21:22:03 +0000 Subject: [PATCH 0426/1057] Revert "Set container to system for aconfig_declarations in AconfigFlags.bp" This reverts commit 2af45e16b7514094f91e83a12dab83e96654aba2. Reason for revert: potentially causing boot time regression Change-Id: If744c038f0ef00178a8b3fc73cc5d674d15bed25 --- Vcn/flags/flags.aconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 15d671dde0..e64823af84 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -1,5 +1,4 @@ package: "android.net.vcn" -container: "system" flag { name: "safe_mode_config" From 612fd73f8d6431b5383d446b9b391ebda78cc751 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 5 Apr 2024 18:30:02 +0000 Subject: [PATCH 0427/1057] VCN CTS to verify feature requirements and service dependencies Bug: 330404031 Test: atest CtsVcnTestCases:VcnSystemRequirementsTest Change-Id: Ifd4874bdd96a0a06b6de35497364ff6498f2cb98 --- .../android/net/vcn/cts/VcnManagerTest.java | 10 +- .../vcn/cts/VcnSystemRequirementsTest.java | 96 +++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 9c30d0555f..d6b702aabb 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -16,7 +16,6 @@ package android.net.vcn.cts; -import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; @@ -37,6 +36,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; +import static android.net.vcn.cts.VcnSystemRequirementsTest.assumeNotNullVcnDependencies; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; @@ -51,7 +51,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 static org.junit.Assume.assumeNotNull; import android.annotation.NonNull; import android.annotation.Nullable; @@ -154,8 +154,10 @@ public class VcnManagerTest extends VcnTestBase { @Before public void setUp() throws Exception { - assumeTrue(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY)); - + // This test assumes the device supports VCN and its dependent system services. Refer to + // VcnSystemRequirementsTest for comprehensive verification of VCN system requirements. + assumeNotNullVcnDependencies(mContext); + assumeNotNull(mVcnManager); getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); // Ensure Internet probing check will be performed on VCN networks diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java new file mode 100644 index 0000000000..2672b3b82f --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn.cts; + +import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + +import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.vcn.VcnManager; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class VcnSystemRequirementsTest { + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + private final Context mContext = InstrumentationRegistry.getContext(); + private final VcnManager mVcnManager = mContext.getSystemService(VcnManager.class); + + private static void assertNotNullVcnDependencies(Context context) { + assertNotNull( + "CarrierConfigManager must be present on this device", + context.getSystemService(CarrierConfigManager.class)); + assertNotNull( + "SubscriptionManager must be present on this device", + context.getSystemService(SubscriptionManager.class)); + assertNotNull( + "ConnectivityManager must be present on this device", + context.getSystemService(ConnectivityManager.class)); + assertNotNull( + "TelephonyManager must be present on this device", + context.getSystemService(TelephonyManager.class)); + } + + // Package private for use in VcnManagerTest + static void assumeNotNullVcnDependencies(Context context) { + try { + assertNotNullVcnDependencies(context); + } catch (AssertionError e) { + assumeTrue(e.toString(), false); + } + } + + /** + * This test verifies that devices with vendor API greater than or equal to V, and which support + * FEATURE_TELEPHONY_SUBSCRIPTION, must also implement VCN and its dependent system services. + */ + @Test + public void testVcnAndDependenciesOnVOrNewerDevices() throws Exception { + final boolean hasFeatureTelSubscription = + mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION); + assumeTrue(getVsrApiLevel() >= VENDOR_API_FOR_ANDROID_V); + assumeTrue(hasFeatureTelSubscription); + + assertNotNullVcnDependencies(mContext); + assertNotNull("VcnManager must be present on this device", mVcnManager); + } + + /** + * For devices with vendor API lower than V, it is not mandatory to support VCN or VCN's + * dependent system services. However, if all VCN dependencies are present, the device must + * support VCN. + */ + @Test + public void testVcndDependenciesOnDevicesBeforeV() throws Exception { + assumeTrue(getVsrApiLevel() < VENDOR_API_FOR_ANDROID_V); + assumeNotNullVcnDependencies(mContext); + + assertNotNull("VcnManager must be present on this device", mVcnManager); + } +} From 3a3b3fc2a46059ae7cca1ed09612754046ae1055 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 3 Apr 2024 23:12:50 +0000 Subject: [PATCH 0428/1057] VCN: Refactor getPacketLossRatePercentage to return an object Refactor getPacketLossRatePercentage to return an object instead of an integer. This is for extending the Packet Loss Detector's ability to handle inbound sequence number leap This patch does not include any behavior changes Bug: 332598276 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Change-Id: Ied42e581fb331ab0603225865236779f50cc4881 --- .../IpSecPacketLossDetector.java | 108 ++++++++++++++++-- .../IpSecPacketLossDetectorTest.java | 40 +++++-- 2 files changed, 129 insertions(+), 19 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index ed9fa65dee..c5d3333170 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -16,8 +16,10 @@ package com.android.server.vcn.routeselection; +import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -38,6 +40,10 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.VcnContext; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.BitSet; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -56,8 +62,32 @@ import java.util.concurrent.TimeUnit; public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PACKET_LOSS_UNAVALAIBLE = -1; + private static final int PACKET_LOSS_PERCENT_UNAVAILABLE = -1; + + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"PACKET_LOSS_"}, + value = { + PACKET_LOSS_RATE_VALID, + PACKET_LOSS_RATE_INVALID, + }) + @Target({ElementType.TYPE_USE}) + private @interface PacketLossResultType {} + + /** Indicates a valid packet loss rate is available */ + private static final int PACKET_LOSS_RATE_VALID = 0; + + /** + * Indicates that the detector cannot get a valid packet loss rate due to one of the following + * reasons: + * + *

      + *
    • The replay window did not proceed and thus all packets might have been delivered out of + * order + *
    • There are unexpected errors + *
    + */ + private static final int PACKET_LOSS_RATE_INVALID = 1; // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and @@ -307,24 +337,24 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { return; } - final int packetLossRate = + final PacketLossCalculationResult calculateResult = mPacketLossCalculator.getPacketLossRatePercentage( mLastIpSecTransformState, state, getLogPrefix()); - if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) { + if (calculateResult.getResultType() == PACKET_LOSS_RATE_INVALID) { return; } final String logMsg = - "packetLossRate: " - + packetLossRate + "calculateResult: " + + calculateResult + "% in the past " + (state.getTimestampMillis() - mLastIpSecTransformState.getTimestampMillis()) + "ms"; mLastIpSecTransformState = state; - if (packetLossRate < mPacketLossRatePercentThreshold) { + if (calculateResult.getPacketLossRatePercent() < mPacketLossRatePercentThreshold) { logV(logMsg); onValidationResultReceivedInternal(false /* isFailed */); } else { @@ -343,7 +373,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { @VisibleForTesting(visibility = Visibility.PRIVATE) public static class PacketLossCalculator { /** Calculate the packet loss rate between two timestamps */ - public int getPacketLossRatePercentage( + public PacketLossCalculationResult getPacketLossRatePercentage( @NonNull IpSecTransformState oldState, @NonNull IpSecTransformState newState, String logPrefix) { @@ -359,7 +389,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) { // The replay window did not proceed and all packets might have been delivered out // of order - return PACKET_LOSS_UNAVALAIBLE; + return PacketLossCalculationResult.invalid(); } // Get the expected packet count by assuming there is no packet loss. In this case, SA @@ -386,10 +416,11 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { || actualPktCntDiff < 0 || actualPktCntDiff > expectedPktCntDiff) { logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff"); - return PACKET_LOSS_UNAVALAIBLE; + return PacketLossCalculationResult.invalid(); } - return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + final int percent = 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + return PacketLossCalculationResult.valid(percent); } } @@ -409,4 +440,59 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) { return BitSet.valueOf(state.getReplayBitmap()).cardinality(); } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class PacketLossCalculationResult { + @PacketLossResultType private final int mResultType; + private final int mPacketLossRatePercent; + + private PacketLossCalculationResult(@PacketLossResultType int type, int percent) { + mResultType = type; + mPacketLossRatePercent = percent; + } + + /** Construct an instance that contains a valid packet loss rate */ + public static PacketLossCalculationResult valid(int percent) { + return new PacketLossCalculationResult(PACKET_LOSS_RATE_VALID, percent); + } + + /** Construct an instance indicating the inability to get a valid packet loss rate */ + public static PacketLossCalculationResult invalid() { + return new PacketLossCalculationResult( + PACKET_LOSS_RATE_INVALID, PACKET_LOSS_PERCENT_UNAVAILABLE); + } + + @PacketLossResultType + public int getResultType() { + return mResultType; + } + + public int getPacketLossRatePercent() { + return mPacketLossRatePercent; + } + + @Override + public int hashCode() { + return Objects.hash(mResultType, mPacketLossRatePercent); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof PacketLossCalculationResult)) { + return false; + } + + final PacketLossCalculationResult rhs = (PacketLossCalculationResult) other; + return mResultType == rhs.mResultType + && mPacketLossRatePercent == rhs.mPacketLossRatePercent; + } + + @Override + public String toString() { + return "mResultType: " + + mResultType + + " | mPacketLossRatePercent: " + + mPacketLossRatePercent; + } + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index fdf8fb8d3c..0a83a53a7b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -19,7 +19,6 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; -import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; @@ -44,6 +43,7 @@ import android.net.IpSecTransformState; import android.os.OutcomeReceiver; import android.os.PowerManager; +import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculationResult; import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator; import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper; import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; @@ -293,7 +293,9 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { } private void checkHandleLossRate( - int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected) + PacketLossCalculationResult mockPacketLossRate, + boolean isLastStateExpectedToUpdate, + boolean isCallbackExpected) throws Exception { final OutcomeReceiver xfrmStateReceiver = startMonitorAndCaptureStateReceiver(); @@ -327,26 +329,32 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { @Test public void testHandleLossRate_validationPass() throws Exception { checkHandleLossRate( - 2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + PacketLossCalculationResult.valid(2), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); } @Test public void testHandleLossRate_validationFail() throws Exception { checkHandleLossRate( - 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + PacketLossCalculationResult.valid(22), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false); } @Test public void testHandleLossRate_resultUnavalaible() throws Exception { checkHandleLossRate( - PACKET_LOSS_UNAVALAIBLE, + PacketLossCalculationResult.invalid(), false /* isLastStateExpectedToUpdate */, false /* isCallbackExpected */); } private void checkGetPacketLossRate( - IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate) + IpSecTransformState oldState, + IpSecTransformState newState, + PacketLossCalculationResult expectedLossRate) throws Exception { assertEquals( expectedLossRate, @@ -362,14 +370,30 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { throws Exception { final IpSecTransformState newState = newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); + checkGetPacketLossRate( + oldState, newState, PacketLossCalculationResult.valid(expectedDataLossRate)); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, + int rxSeqNo, + int packetCount, + int packetInWin, + PacketLossCalculationResult expectedDataLossRate) + throws Exception { + final IpSecTransformState newState = + newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); checkGetPacketLossRate(oldState, newState, expectedDataLossRate); } @Test public void testGetPacketLossRate_replayWindowUnchanged() throws Exception { checkGetPacketLossRate( - mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE); - checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE); + mTransformStateInitial, + mTransformStateInitial, + PacketLossCalculationResult.invalid()); + checkGetPacketLossRate( + mTransformStateInitial, 3000, 2000, 2000, PacketLossCalculationResult.invalid()); } @Test From 7e52cc07b11afc15360e875c9aa0dca737c57e65 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 3 Apr 2024 23:12:50 +0000 Subject: [PATCH 0429/1057] VCN: Handle sequence number leap in packet loss detector This pacth enables IPsec packet loss detector to handle the case when there is an intentional sequence number leap on the server's downlink. Previously the detector assumes that sequence number will always increase consecutively, which is not true. During load balancing the server might add a big leap on the sequence number intentionally. In such case a high packet loss rate does not always indicate a lossy network. At the same time, a low loss rate does mean the network is not lossy Bug: 332598276 Test: atest FrameworksVcnTests (new tests) && atest CtsVcnTestCases Change-Id: I163cb274d293a305499fd60f7ad6eed394af5a4d --- Vcn/flags/flags.aconfig | 10 ++ .../src/android/net/vcn/VcnManager.java | 17 +++ .../IpSecPacketLossDetector.java | 78 +++++++++++- .../routeselection/NetworkMetricMonitor.java | 5 + .../IpSecPacketLossDetectorTest.java | 111 +++++++++++++++++- .../NetworkEvaluationTestBase.java | 1 + 6 files changed, 213 insertions(+), 9 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index e64823af84..6fde398528 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -34,4 +34,14 @@ flag{ namespace: "vcn" description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change" bug: "323238888" +} + +flag{ + name: "handle_seq_num_leap" + namespace: "vcn" + description: "Do not report bad network when there is a suspected sequence number leap" + bug: "332598276" + metadata { + purpose: PURPOSE_BUGFIX + } } \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 6246dd77fd..91cdf8d8fc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -123,6 +123,22 @@ public class VcnManager { public static final String VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY = "vcn_network_selection_ipsec_packet_loss_percent_threshold"; + /** + * Key for detecting unusually large increases in IPsec packet sequence numbers. + * + *

    If the sequence number increases by more than this value within a second, it may indicate + * an intentional leap on the server's downlink. To avoid false positives, the packet loss + * detector will suppress loss reporting. + * + *

    By default, there's no maximum limit enforced, prioritizing detection of lossy networks. + * To reduce false positives, consider setting an appropriate maximum threshold. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY = + "vcn_network_selection_max_seq_num_increase_per_second"; + /** * Key for the list of timeouts in minute to stop penalizing an underlying network candidate * @@ -180,6 +196,7 @@ public class VcnManager { VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY, VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index c5d3333170..206523a6e9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -70,6 +70,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { value = { PACKET_LOSS_RATE_VALID, PACKET_LOSS_RATE_INVALID, + PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP, }) @Target({ElementType.TYPE_USE}) private @interface PacketLossResultType {} @@ -89,6 +90,16 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { */ private static final int PACKET_LOSS_RATE_INVALID = 1; + /** + * The sequence number increase is unusually large and might be caused an intentional leap on + * the server's downlink + * + *

    Inbound sequence number will not always increase consecutively. During load balancing the + * server might add a big leap on the sequence number intentionally. In such case a high packet + * loss rate does not always indicate a lossy network + */ + private static final int PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP = 2; + // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and // Security"). For audio and video streaming, above 10-12% packet loss is unacceptable (as per @@ -98,8 +109,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20; + // By default, there's no maximum limit enforced + private static final int MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED = -1; + private long mPollIpSecStateIntervalMs; private final int mPacketLossRatePercentThreshold; + private int mMaxSeqNumIncreasePerSecond; @NonNull private final Handler mHandler; @NonNull private final PowerManager mPowerManager; @@ -138,6 +153,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); // Register for system broadcasts to monitor idle mode change final IntentFilter intentFilter = new IntentFilter(); @@ -202,6 +218,24 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { return IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + static int getMaxSeqNumIncreasePerSecond(@Nullable PersistableBundleWrapper carrierConfig) { + int maxSeqNumIncrease = MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED; + if (Flags.handleSeqNumLeap() && carrierConfig != null) { + maxSeqNumIncrease = + carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY, + MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED); + } + + if (maxSeqNumIncrease < MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { + logE(TAG, "Invalid value of MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY " + maxSeqNumIncrease); + return MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED; + } + + return maxSeqNumIncrease; + } + @Override protected void onSelectedUnderlyingNetworkChanged() { if (!isSelectedUnderlyingNetwork()) { @@ -237,6 +271,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // The already scheduled event will not be affected. The followup events will be scheduled // with the new interval mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + + if (Flags.handleSeqNumLeap()) { + mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); + } } @Override @@ -339,7 +377,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { final PacketLossCalculationResult calculateResult = mPacketLossCalculator.getPacketLossRatePercentage( - mLastIpSecTransformState, state, getLogPrefix()); + mLastIpSecTransformState, + state, + mMaxSeqNumIncreasePerSecond, + getLogPrefix()); if (calculateResult.getResultType() == PACKET_LOSS_RATE_INVALID) { return; @@ -356,11 +397,18 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mLastIpSecTransformState = state; if (calculateResult.getPacketLossRatePercent() < mPacketLossRatePercentThreshold) { logV(logMsg); + + // In both "valid" or "unusual_seq_num_leap" cases, notify that the network has passed + // the validation onValidationResultReceivedInternal(false /* isFailed */); } else { logInfo(logMsg); - onValidationResultReceivedInternal(true /* isFailed */); + if (calculateResult.getResultType() == PACKET_LOSS_RATE_VALID) { + onValidationResultReceivedInternal(true /* isFailed */); + } + + // In both "valid" or "unusual_seq_num_leap" cases, trigger network validation if (Flags.validateNetworkOnIpsecLoss()) { // Trigger re-validation of the underlying network; if it fails, the VCN will // attempt to migrate away. @@ -376,6 +424,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { public PacketLossCalculationResult getPacketLossRatePercentage( @NonNull IpSecTransformState oldState, @NonNull IpSecTransformState newState, + int maxSeqNumIncreasePerSecond, String logPrefix) { logVIpSecTransform("oldState", oldState, logPrefix); logVIpSecTransform("newState", newState, logPrefix); @@ -392,6 +441,22 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { return PacketLossCalculationResult.invalid(); } + boolean isUnusualSeqNumLeap = false; + + // Handle sequence number leap + if (Flags.handleSeqNumLeap() + && maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { + final long timeDiffMillis = + newState.getTimestampMillis() - oldState.getTimestampMillis(); + final long maxSeqNumIncrease = timeDiffMillis * maxSeqNumIncreasePerSecond / 1000; + + // Sequence numbers are unsigned 32-bit values. If maxSeqNumIncrease overflows, + // isUnusualSeqNumLeap can never be true. + if (maxSeqNumIncrease >= 0 && newSeqHi - oldSeqHi >= maxSeqNumIncrease) { + isUnusualSeqNumLeap = true; + } + } + // Get the expected packet count by assuming there is no packet loss. In this case, SA // should receive all packets whose sequence numbers are smaller than the lower bound of // the replay window AND the packets received within the window. @@ -420,7 +485,9 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { } final int percent = 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); - return PacketLossCalculationResult.valid(percent); + return isUnusualSeqNumLeap + ? PacketLossCalculationResult.unusualSeqNumLeap(percent) + : PacketLossCalculationResult.valid(percent); } } @@ -462,6 +529,11 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { PACKET_LOSS_RATE_INVALID, PACKET_LOSS_PERCENT_UNAVAILABLE); } + /** Construct an instance indicating that there is an unusual sequence number leap */ + public static PacketLossCalculationResult unusualSeqNumLeap(int percent) { + return new PacketLossCalculationResult(PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP, percent); + } + @PacketLossResultType public int getResultType() { return mResultType; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index a1b212f8d3..b9b10606a1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -272,6 +272,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { } } + protected static void logE(String className, String msgWithPrefix) { + Slog.w(className, msgWithPrefix); + LOCAL_LOG.log("[ERROR ] " + className + msgWithPrefix); + } + protected static void logWtf(String className, String msgWithPrefix) { Slog.wtf(className, msgWithPrefix); LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 0a83a53a7b..68a2ad7e1a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -17,8 +17,10 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; @@ -65,6 +67,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { private static final int REPLAY_BITMAP_LEN_BYTE = 512; private static final int REPLAY_BITMAP_LEN_BIT = REPLAY_BITMAP_LEN_BYTE * 8; private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD = 5; + private static final int MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED = -1; private static final long POLL_IPSEC_STATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(30L); @Mock private IpSecTransformWrapper mIpSecTransform; @@ -91,6 +94,9 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), anyInt())) .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED); when(mDependencies.getPacketLossCalculator()).thenReturn(mPacketLossCalculator); @@ -112,6 +118,20 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { .build(); } + private static IpSecTransformState newNextTransformState( + IpSecTransformState before, + long timeDiffMillis, + long rxSeqNoDiff, + long packtCountDiff, + int packetInWin) { + return new IpSecTransformState.Builder() + .setTimestampMillis(before.getTimestampMillis() + timeDiffMillis) + .setRxHighestSequenceNumber(before.getRxHighestSequenceNumber() + rxSeqNoDiff) + .setPacketCount(before.getPacketCount() + packtCountDiff) + .setReplayBitmap(newReplayBitmap(packetInWin)) + .build(); + } + private static byte[] newReplayBitmap(int receivedPktCnt) { final BitSet bitSet = new BitSet(REPLAY_BITMAP_LEN_BIT); for (int i = 0; i < receivedPktCnt; i++) { @@ -165,7 +185,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verify the first polled state is stored assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); // Verify next poll is scheduled assertNull(mTestLooper.nextMessage()); @@ -278,7 +298,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1))); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); } @Test @@ -289,7 +309,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { xfrmStateReceiver.onError(new RuntimeException("Test")); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); } private void checkHandleLossRate( @@ -301,7 +321,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { startMonitorAndCaptureStateReceiver(); doReturn(mockPacketLossRate) .when(mPacketLossCalculator) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); // Mock receiving two states with mTransformStateInitial and an arbitrary transformNew final IpSecTransformState transformNew = newTransformState(1, 1, newReplayBitmap(1)); @@ -311,7 +331,10 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verifications verify(mPacketLossCalculator) .getPacketLossRatePercentage( - eq(mTransformStateInitial), eq(transformNew), anyString()); + eq(mTransformStateInitial), + eq(transformNew), + eq(MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED), + anyString()); if (isLastStateExpectedToUpdate) { assertEquals(transformNew, mIpSecPacketLossDetector.getLastTransformState()); @@ -351,6 +374,22 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { false /* isCallbackExpected */); } + @Test + public void testHandleLossRate_unusualSeqNumLeap_highLossRate() throws Exception { + checkHandleLossRate( + PacketLossCalculationResult.unusualSeqNumLeap(22), + true /* isLastStateExpectedToUpdate */, + false /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_unusualSeqNumLeap_lowLossRate() throws Exception { + checkHandleLossRate( + PacketLossCalculationResult.unusualSeqNumLeap(2), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); + } + private void checkGetPacketLossRate( IpSecTransformState oldState, IpSecTransformState newState, @@ -358,7 +397,8 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { throws Exception { assertEquals( expectedLossRate, - mPacketLossCalculator.getPacketLossRatePercentage(oldState, newState, TAG)); + mPacketLossCalculator.getPacketLossRatePercentage( + oldState, newState, MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED, TAG)); } private void checkGetPacketLossRate( @@ -443,6 +483,45 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10); } + private void checkGetPktLossRate_unusualSeqNumLeap( + int maxSeqNumIncreasePerSecond, + int timeDiffMillis, + int rxSeqNoDiff, + PacketLossCalculationResult expected) + throws Exception { + final IpSecTransformState oldState = mTransformStateInitial; + final IpSecTransformState newState = + newNextTransformState( + oldState, + timeDiffMillis, + rxSeqNoDiff, + 1 /* packtCountDiff */, + 1 /* packetInWin */); + + assertEquals( + expected, + mPacketLossCalculator.getPacketLossRatePercentage( + oldState, newState, maxSeqNumIncreasePerSecond, TAG)); + } + + @Test + public void testGetPktLossRate_unusualSeqNumLeap() throws Exception { + checkGetPktLossRate_unusualSeqNumLeap( + 10000 /* maxSeqNumIncreasePerSecond */, + (int) TimeUnit.SECONDS.toMillis(2L), + 30000 /* rxSeqNoDiff */, + PacketLossCalculationResult.unusualSeqNumLeap(100)); + } + + @Test + public void testGetPktLossRate_unusualSeqNumLeap_smallSeqNumDiff() throws Exception { + checkGetPktLossRate_unusualSeqNumLeap( + 10000 /* maxSeqNumIncreasePerSecond */, + (int) TimeUnit.SECONDS.toMillis(2L), + 5000 /* rxSeqNoDiff */, + PacketLossCalculationResult.valid(100)); + } + // Verify the polling event is scheduled with expected delays private void verifyPollEventDelayAndScheduleNext(long expectedDelayMs) { if (expectedDelayMs > 0) { @@ -469,4 +548,24 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verify the 3rd poll is scheduled with configured delay verifyPollEventDelayAndScheduleNext(POLL_IPSEC_STATE_INTERVAL_MS); } + + @Test + public void testGetMaxSeqNumIncreasePerSecond() throws Exception { + final int seqNumLeapNegative = 500_000; + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(seqNumLeapNegative); + assertEquals(seqNumLeapNegative, getMaxSeqNumIncreasePerSecond(mCarrierConfig)); + } + + @Test + public void testGetMaxSeqNumIncreasePerSecond_negativeValue() throws Exception { + final int seqNumLeapNegative = -10; + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(seqNumLeapNegative); + assertEquals( + MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED, + getMaxSeqNumIncreasePerSecond(mCarrierConfig)); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index af6daa17e2..6189fb0834 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -123,6 +123,7 @@ public abstract class NetworkEvaluationTestBase { mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); + mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP); when(mNetwork.getNetId()).thenReturn(-1); From aab9cbd2a535bb7128cbd3239d510b4fdccc63ff Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 9 Apr 2024 01:23:04 +0000 Subject: [PATCH 0430/1057] VCN: Ignore packet loss detection when there is too few traffic When the expected received packet number is smaller than 10, the packet loss detection result will be ignored because the sample size is too small to ensure a reliable result. This patch also fixes the bug where the detector does not update ths packet loss threshold when carrier config updates Bug: 332598276 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Change-Id: Iccc47e83c48699d139029420572e2a2616c357cd --- .../routeselection/IpSecPacketLossDetector.java | 16 +++++++++++++++- .../IpSecPacketLossDetectorTest.java | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 206523a6e9..3619253749 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -64,6 +64,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final int PACKET_LOSS_PERCENT_UNAVAILABLE = -1; + // Ignore the packet loss detection result if the expected packet number is smaller than 10. + // Solarwinds NPM uses 10 ICMP echos to calculate packet loss rate (as per + // https://thwack.solarwinds.com/products/network-performance-monitor-npm/f/forum/63829/how-is-packet-loss-calculated) + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int MIN_VALID_EXPECTED_RX_PACKET_NUM = 10; + @Retention(RetentionPolicy.SOURCE) @IntDef( prefix = {"PACKET_LOSS_"}, @@ -85,6 +91,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { *

      *
    • The replay window did not proceed and thus all packets might have been delivered out of * order + *
    • The expected received packet number is too small and thus the detection result is not + * reliable *
    • There are unexpected errors *
    */ @@ -113,7 +121,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final int MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED = -1; private long mPollIpSecStateIntervalMs; - private final int mPacketLossRatePercentThreshold; + private int mPacketLossRatePercentThreshold; private int mMaxSeqNumIncreasePerSecond; @NonNull private final Handler mHandler; @@ -273,6 +281,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); if (Flags.handleSeqNumLeap()) { + mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); } } @@ -476,6 +485,11 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { + " actualPktCntDiff: " + actualPktCntDiff); + if (Flags.handleSeqNumLeap() && expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) { + // The sample size is too small to ensure a reliable detection result + return PacketLossCalculationResult.invalid(); + } + if (expectedPktCntDiff < 0 || expectedPktCntDiff == 0 || actualPktCntDiff < 0 diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 68a2ad7e1a..c8b60e5c33 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -20,6 +20,7 @@ import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; @@ -436,6 +437,21 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { mTransformStateInitial, 3000, 2000, 2000, PacketLossCalculationResult.invalid()); } + @Test + public void testGetPacketLossRate_expectedPacketNumTooFew() throws Exception { + final int oldRxNo = 4096; + final int oldPktCnt = 4096; + final int pktCntDiff = MIN_VALID_EXPECTED_RX_PACKET_NUM - 1; + final byte[] bitmapReceiveAll = newReplayBitmap(4096); + + final IpSecTransformState oldState = + newTransformState(oldRxNo, oldPktCnt, bitmapReceiveAll); + final IpSecTransformState newState = + newTransformState(oldRxNo + pktCntDiff, oldPktCnt + pktCntDiff, bitmapReceiveAll); + + checkGetPacketLossRate(oldState, newState, PacketLossCalculationResult.invalid()); + } + @Test public void testGetPacketLossRate_againstInitialState() throws Exception { checkGetPacketLossRate(mTransformStateInitial, 7000, 7001, 4096, 0); From 41d53548d5402a524604976bc5452198b1f575d3 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 10 Apr 2024 22:02:24 +0000 Subject: [PATCH 0431/1057] VCN CTS: Deflake tests by improving onLost verifications The test tried to use #waitForLost to verify that a specific network was reported onLost. However this verification logic is not always reliable. All lost networks are stored in mLostHistory and #waitForLost only returns the head of the mLostHistory. When mLostHistory has multiple networks(due to onLost for the same network called multiple times or multiple networks have matched the requests), the expected network might not be in the head. This patch fixes the issue by looking through all the networks in mLostHistory instead of just the head. Bug: 333924896 Test: atest VcnManagerTest for 100 times and all passed; without the fix the issue can be reproduced by running test for 20 times Change-Id: Ie0a2da2bed5a8ebcfc5399b6211a324c318b4cca --- .../net/vcn/cts/TestNetworkWrapper.java | 23 +++++++++++++++++++ .../android/net/vcn/cts/VcnManagerTest.java | 3 +-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java index 60fe35cdbc..966b5c5f05 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/TestNetworkWrapper.java @@ -18,6 +18,8 @@ package android.net.vcn.cts; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static org.junit.Assert.fail; + import android.annotation.NonNull; import android.content.Context; import android.ipsec.ike.cts.IkeTunUtils; @@ -381,6 +383,27 @@ public class TestNetworkWrapper implements AutoCloseable { return mLostHistory.poll(NETWORK_CB_TIMEOUT_MS, TimeUnit.MILLISECONDS); } + /** + * Continue polling from the mLostHistory until the expected network is found + * + *

    Callers should prefer this method over #waitForLost if they care about a specific + * network. #waitForLost only returns the head of the mLostHistory. Since there might be + * more than one networks that have been reported by #onLost and also #onLost for the same + * network might called multiple times, the target network might not always be in the head + * of the queue + */ + public void waitForLostNetwork(Network network) throws InterruptedException { + final long endTime = System.currentTimeMillis() + NETWORK_CB_TIMEOUT_MS; + + while (System.currentTimeMillis() < endTime) { + if (Objects.equals(network, waitForLost())) { + return; + } + } + + fail("Timeout on waitForLostNetwork " + network); + } + public CapabilitiesChangedEvent waitForOnCapabilitiesChanged() throws Exception { return waitForOnCapabilitiesChanged(NETWORK_CB_TIMEOUT_MS); } diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index d6b702aabb..a1e5c351d8 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -1297,8 +1297,7 @@ public class VcnManagerTest extends VcnTestBase { timeoutMillis); // Verify that VCN Network is also lost in safemode - final Network lostVcnNetwork = cellNetworkCb.waitForLost(); - assertEquals(vcnSetupResult.vcnNetwork, lostVcnNetwork); + cellNetworkCb.waitForLostNetwork(vcnSetupResult.vcnNetwork); verifyVcnStatus(subGrp, VCN_STATUS_CODE_SAFE_MODE); From 95d50c97eff56b6094e6f9aec39a894df82e5c3f Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 16 Apr 2024 23:30:21 +0000 Subject: [PATCH 0432/1057] Check the existence of IpSecTransformState API with try catch IpSecTransformState is a new API that exposed from a mainline module. Ideally before SDK finalization, platform should check the API flag com.android.net.flags.ipsec_transform_state before calling the API. However the flag is defined in mainline module is not accessible from the platform. Thus previously a placeholder flag was used. This patch removes the usage of the placeholder flag. Instead the code will check the availability of the API with a try catch block Bug: 328844044 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: NONE mainline API flag not accessible; using try catch block to gate the behavior Change-Id: Ibbcb14817a6d714cdc99cf0894f1fc935a602a2c --- .../src/com/android/server/vcn/VcnContext.java | 14 +++++++++++--- .../routeselection/NetworkEvaluationTestBase.java | 1 - 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 1383708d8a..6a4c9c26d3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -18,6 +18,7 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; +import android.net.IpSecTransformState; import android.net.vcn.FeatureFlags; import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; @@ -34,7 +35,6 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; - @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -49,7 +49,6 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); - mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl(); } @NonNull @@ -76,7 +75,16 @@ public class VcnContext { } public boolean isFlagIpSecTransformStateEnabled() { - return mCoreNetFeatureFlags.ipsecTransformState(); + // TODO: b/328844044: Ideally this code should gate the behavior by checking the + // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible + // right now. We should either update the code when the flag is accessible or remove the + // legacy behavior after VIC SDK finalization + try { + new IpSecTransformState.Builder(); + return true; + } catch (Exception e) { + return false; + } } @NonNull diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index af6daa17e2..97617f9abc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -107,7 +107,6 @@ public abstract class NetworkEvaluationTestBase { @Mock protected Context mContext; @Mock protected Network mNetwork; @Mock protected FeatureFlags mFeatureFlags; - @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected ConnectivityManager mConnectivityManager; @Mock protected TelephonyManager mTelephonyManager; From 12c1deff84193a7b4946f4461bf44a08eeec7939 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 17 Apr 2024 01:42:55 +0000 Subject: [PATCH 0433/1057] Encode IkeSessionParams using getIkeOptions This patch integrates IkeSessionParams#getIkeOptions into the process of making IkeSessionParams a PersistableBundle. With this patch, the encoding process no longer depends on a static IKE_OPTIONS list. Thus if a new IKE Option is added in the IKE module, it will be taken care of without needing to update the IKE_OPTIONS list Bug: 185941731 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Test: Manually removed options from IKE_OPTIONS and tests still passed Flag: NONE mainline API flag not accessible; using try catch block to gate the behavior Change-Id: I2c1a9ca1731362b1ab666e5b804911d8b0ca45e7 --- .../IkeSessionParamsUtils.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index d681a2c38f..d1531a119a 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -162,12 +162,21 @@ public final class IkeSessionParamsUtils { result.putInt(IP_VERSION_KEY, params.getIpVersion()); result.putInt(ENCAP_TYPE_KEY, params.getEncapType()); - // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new - // IKE_OPTION is defined in IKE module and added in the IkeSessionParams final List enabledIkeOptions = new ArrayList<>(); - for (int option : IKE_OPTIONS) { - if (isIkeOptionValid(option) && params.hasIkeOption(option)) { - enabledIkeOptions.add(option); + + try { + // TODO: b/328844044: Ideally this code should gate the behavior by checking the + // com.android.ipsec.flags.enabled_ike_options_api flag but that flag is not accessible + // right now. We should either update the code when the flag is accessible or remove the + // legacy behavior after VIC SDK finalization + enabledIkeOptions.addAll(params.getIkeOptions()); + } catch (Exception e) { + // getIkeOptions throws. It means the API is not available + enabledIkeOptions.clear(); + for (int option : IKE_OPTIONS) { + if (isIkeOptionValid(option) && params.hasIkeOption(option)) { + enabledIkeOptions.add(option); + } } } From 555dd14e968f1c880aac9eaa4d3a730c4e54aa5a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 10 Apr 2024 19:06:17 +0000 Subject: [PATCH 0434/1057] VCN CTS: Wait for an active sub ID before running tests In the early stage during phone reboot #getDefaultDataSubscriptionId may not return a valid data subId and cause tests to fail. To mitigate these failures and make the tests less flaky, this patch enables tests to wait for the active subscription ID to become available before proceeding. This patch also ensures that airplane mode is disabled before testing. Bug: 331658552 Test: atest CtsVcnTestCases Flag: TEST_ONLY Change-Id: I41fe297c14433f5f64c1f71395f042027b565390 --- .../android/net/vcn/cts/VcnManagerTest.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index d6b702aabb..0cc05a492c 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -41,12 +41,13 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.compatibility.common.util.TestUtils.waitUntil; import static com.android.internal.util.HexDump.hexStringToByteArray; 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.assertNull; import static org.junit.Assert.assertTrue; @@ -119,6 +120,8 @@ public class VcnManagerTest extends VcnTestBase { private static final int TIMEOUT_MS = 500; private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35); + private static final int ACTIVE_SUB_ID_TIMEOUT_SECONDS = 60; + private static final Executor INLINE_EXECUTOR = Runnable::run; private static final int TEST_NETWORK_MTU = 1500; @@ -162,6 +165,8 @@ public class VcnManagerTest extends VcnTestBase { // Ensure Internet probing check will be performed on VCN networks setCaptivePortalMode(mContext, CAPTIVE_PORTAL_MODE_PROMPT); + + runShellCommand("cmd connectivity airplane-mode disable"); } @After @@ -195,13 +200,17 @@ public class VcnManagerTest extends VcnTestBase { return buildVcnConfigBase().setIsTestModeProfile().build(); } - private int verifyAndGetValidDataSubId() { - final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - assertNotEquals( + private int verifyAndGetValidDataSubId() throws Exception { + // Wait for an active sub ID to mitigate the cuttlefish test issue where the CTS will + // start before a valid data subId is ready. In most cases this should return immediately + // without needing to wait. + waitUntil( "There must be an active data subscription to complete CTS", - INVALID_SUBSCRIPTION_ID, - dataSubId); - return dataSubId; + ACTIVE_SUB_ID_TIMEOUT_SECONDS, + () -> + SubscriptionManager.getDefaultDataSubscriptionId() + != INVALID_SUBSCRIPTION_ID); + return SubscriptionManager.getDefaultDataSubscriptionId(); } @Test(expected = SecurityException.class) From e4afa4fb5c998410aaa845c5ff39945158e8ab12 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 17 Apr 2024 18:52:26 +0000 Subject: [PATCH 0435/1057] Dump IkeSession in VcnGatewayConnection#dump Bug: 288599290 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Test: adb shell dumpsys vcn_management FLAG: NONE mainline API flag not accessible; using try catch block to gate the behaviors Change-Id: I6e868b7c51d32754be53944957c79ee2413a2d14 --- .../src/com/android/server/vcn/Vcn.java | 4 ++++ .../server/vcn/VcnGatewayConnection.java | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 37f04501bf..5a5f7ef7b2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -626,8 +626,12 @@ public class Vcn extends Handler { * Dumps the state of this Vcn for logging and debugging purposes. * *

    PII and credentials MUST NEVER be dumped here. + * + *

    This method is not thread safe and MUST run on the VCN thread. */ public void dump(IndentingPrintWriter pw) { + mVcnContext.ensureRunningOnLooperThread(); + pw.println("Vcn (" + mSubscriptionGroup + "):"); pw.increaseIndent(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 3094b18209..8d378a021f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -2580,8 +2580,12 @@ public class VcnGatewayConnection extends StateMachine { * Dumps the state of this VcnGatewayConnection for logging and debugging purposes. * *

    PII and credentials MUST NEVER be dumped here. + * + *

    This method is not thread safe and MUST run on the VCN thread. */ public void dump(IndentingPrintWriter pw) { + mVcnContext.ensureRunningOnLooperThread(); + pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):"); pw.increaseIndent(); @@ -2602,6 +2606,19 @@ public class VcnGatewayConnection extends StateMachine { mUnderlyingNetworkController.dump(pw); pw.println(); + if (mIkeSession == null) { + pw.println("mIkeSession: null"); + } else { + pw.println("mIkeSession:"); + + // Add a try catch block in case IkeSession#dump is not thread-safe + try { + mIkeSession.dump(pw); + } catch (Exception e) { + Slog.wtf(TAG, "Failed to dump IkeSession: " + e); + } + } + pw.decreaseIndent(); } @@ -2905,6 +2922,11 @@ public class VcnGatewayConnection extends StateMachine { public void setNetwork(@NonNull Network network) { mImpl.setNetwork(network); } + + /** Dumps the state of the IkeSession */ + public void dump(@NonNull IndentingPrintWriter pw) { + mImpl.dump(pw); + } } /** Proxy Implementation of WakeLock, used for testing. */ From 10b1cce7589b23ac866763a97b6ca9dc81ca6fd8 Mon Sep 17 00:00:00 2001 From: Dennis Shen Date: Fri, 19 Apr 2024 11:57:28 +0000 Subject: [PATCH 0436/1057] Revert^2 "Set container to system for aconfig_declarations in AconfigFlags.bp" This reverts commit df5d8a5494bacfbb9b67f7f97f3d4762b0f9bdf5. Reason for revert: Performance regression is gone based on go/abtd verification, reintroduce the change. Change-Id: I0dceae0d564612925f23002ac76fb60bbbe599f1 --- Vcn/flags/flags.aconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 6fde398528..fea2c253e7 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -1,4 +1,5 @@ package: "android.net.vcn" +container: "system" flag { name: "safe_mode_config" From 02bd309336b45ed5e07e3f7b22ba1e30a24390ea Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 26 Apr 2024 21:39:36 +0000 Subject: [PATCH 0437/1057] Fix the assumption check in VCN CTS Bug: 334750038 Test: atest CtsVcnTestCases Flag: TEST_ONLY Change-Id: I7f28347bcc0d038a7a5a424c0bba576e75ccb528 --- .../android/net/vcn/cts/VcnManagerTest.java | 26 ++++++++++++++----- .../vcn/cts/VcnSystemRequirementsTest.java | 22 ---------------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 41b426c9f0..7d13fea0b2 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -16,6 +16,8 @@ package android.net.vcn.cts; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; import static android.ipsec.ike.cts.IkeTunUtils.PortPair; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; import static android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; @@ -36,7 +38,6 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; -import static android.net.vcn.cts.VcnSystemRequirementsTest.assumeNotNullVcnDependencies; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; @@ -52,7 +53,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.assumeNotNull; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.annotation.Nullable; @@ -157,10 +158,23 @@ public class VcnManagerTest extends VcnTestBase { @Before public void setUp() throws Exception { - // This test assumes the device supports VCN and its dependent system services. Refer to - // VcnSystemRequirementsTest for comprehensive verification of VCN system requirements. - assumeNotNullVcnDependencies(mContext); - assumeNotNull(mVcnManager); + final boolean hasFeatureTelephony = + mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY); + final boolean hasFeatureTelSubscription = + mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION); + final boolean hasTelephonyFlag = hasFeatureTelephony || hasFeatureTelSubscription; + + // Before V, only devices with FEATURE_TELEPHONY are required to run the tests. Starting + // from V, tests are also required on following cases: + // + // Device that has a non-null VcnManager even if it has neither of FEATURE_TELEPHONY or + // FEATURE_TELEPHONY_SUBSCRIPTION. + // + // Device that has FEATURE_TELEPHONY_SUBSCRIPTION. This should not be a new requirement + // since before V devices with FEATURE_TELEPHONY_SUBSCRIPTION are already enforced to have + // FEATURE_TELEPHONY. + assumeTrue(hasTelephonyFlag || mVcnManager != null); + getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); // Ensure Internet probing check will be performed on VCN networks diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java index 2672b3b82f..b095d7f674 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnSystemRequirementsTest.java @@ -57,15 +57,6 @@ public class VcnSystemRequirementsTest { context.getSystemService(TelephonyManager.class)); } - // Package private for use in VcnManagerTest - static void assumeNotNullVcnDependencies(Context context) { - try { - assertNotNullVcnDependencies(context); - } catch (AssertionError e) { - assumeTrue(e.toString(), false); - } - } - /** * This test verifies that devices with vendor API greater than or equal to V, and which support * FEATURE_TELEPHONY_SUBSCRIPTION, must also implement VCN and its dependent system services. @@ -80,17 +71,4 @@ public class VcnSystemRequirementsTest { assertNotNullVcnDependencies(mContext); assertNotNull("VcnManager must be present on this device", mVcnManager); } - - /** - * For devices with vendor API lower than V, it is not mandatory to support VCN or VCN's - * dependent system services. However, if all VCN dependencies are present, the device must - * support VCN. - */ - @Test - public void testVcndDependenciesOnDevicesBeforeV() throws Exception { - assumeTrue(getVsrApiLevel() < VENDOR_API_FOR_ANDROID_V); - assumeNotNullVcnDependencies(mContext); - - assertNotNull("VcnManager must be present on this device", mVcnManager); - } } From 359ee4691e3edc6f4c42edb20cdb498d8d417c69 Mon Sep 17 00:00:00 2001 From: Oriol Prieto Gasco Date: Tue, 30 Apr 2024 20:05:05 +0000 Subject: [PATCH 0438/1057] RESTRICT AUTOMERGE Set the container field of aconfig flags Test: printflags --format='{package}:{container}:' | grep "::" Bug: 312769710 Flag: NONE Change-Id: I84fda0d5e9813940609436d825738ff786908ff0 --- Vcn/flags/flags.aconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 6fde398528..fea2c253e7 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -1,4 +1,5 @@ package: "android.net.vcn" +container: "system" flag { name: "safe_mode_config" From d978bdcffa2bf105ee58a7fa895f57fdcfaf3195 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 30 Apr 2024 15:39:47 +0000 Subject: [PATCH 0439/1057] Support disabling IPsec packet loss detector Allow disabling detector for better configurability Bug: 336638836 Test: atest FrameworksVcnTests(new tests) && atest CtsVcnTestCases Flag: android.net.vcn.allow_disable_ipsec_loss_detector Change-Id: Icd7183d12fb287399a500ea9c0ee4125c749275c --- Vcn/flags/flags.aconfig | 10 ++++ .../IpSecPacketLossDetector.java | 23 +++++++- .../IpSecPacketLossDetectorTest.java | 53 +++++++++++++++++++ .../NetworkEvaluationTestBase.java | 1 + 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 6fde398528..eca0e93729 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -44,4 +44,14 @@ flag{ metadata { purpose: PURPOSE_BUGFIX } +} + +flag{ + name: "allow_disable_ipsec_loss_detector" + namespace: "vcn" + description: "Allow disabling IPsec packet loss detector" + bug: "336638836" + metadata { + purpose: PURPOSE_BUGFIX + } } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 3619253749..4742532236 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -115,6 +115,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // validation failure. private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT = 12; + /** Carriers can disable the detector by setting the threshold to -1 */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR = -1; + private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20; // By default, there's no maximum limit enforced @@ -271,7 +275,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // When multiple parallel inbound transforms are created, NetworkMetricMonitor will be // enabled on the last one as a sample mInboundTransform = inboundTransform; - start(); + + if (!Flags.allowDisableIpsecLossDetector() || canStart()) { + start(); + } } @Override @@ -284,6 +291,14 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); } + + if (Flags.allowDisableIpsecLossDetector() && canStart() != isStarted()) { + if (canStart()) { + start(); + } else { + stop(); + } + } } @Override @@ -298,6 +313,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L); } + private boolean canStart() { + return mInboundTransform != null + && mPacketLossRatePercentThreshold + != IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR; + } + @Override protected void start() { super.start(); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index c8b60e5c33..441a4ae6d9 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -20,6 +20,7 @@ import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; @@ -584,4 +585,56 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED, getMaxSeqNumIncreasePerSecond(mCarrierConfig)); } + + private IpSecPacketLossDetector newDetectorAndSetTransform(int threshold) throws Exception { + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), + anyInt())) + .thenReturn(threshold); + + final IpSecPacketLossDetector detector = + new IpSecPacketLossDetector( + mVcnContext, + mNetwork, + mCarrierConfig, + mMetricMonitorCallback, + mDependencies); + + detector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + detector.setInboundTransformInternal(mIpSecTransform); + + return detector; + } + + @Test + public void testDisableAndEnableDetectorWithCarrierConfig() throws Exception { + final IpSecPacketLossDetector detector = + newDetectorAndSetTransform(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR); + + assertFalse(detector.isStarted()); + + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), + anyInt())) + .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + detector.setCarrierConfig(mCarrierConfig); + + assertTrue(detector.isStarted()); + } + + @Test + public void testEnableAndDisableDetectorWithCarrierConfig() throws Exception { + final IpSecPacketLossDetector detector = + newDetectorAndSetTransform(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + + assertTrue(detector.isStarted()); + + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), + anyInt())) + .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR); + detector.setCarrierConfig(mCarrierConfig); + + assertFalse(detector.isStarted()); + } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index edad67896e..0439d5f54e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -123,6 +123,7 @@ public abstract class NetworkEvaluationTestBase { mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_DISABLE_IPSEC_LOSS_DETECTOR); when(mNetwork.getNetId()).thenReturn(-1); From 0468b73169c7e827bb26dfc8389bff905ec2bb52 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 28 Nov 2023 02:42:37 +0000 Subject: [PATCH 0440/1057] Make VCN HSUM compatible Require VCN to be used by a "main user" instead of a "system user" since "system user" will no longer be a full user on HSUM devices Bug: 310310661 Test: FrameworksVcnTests, CtsVcnTestCases on non-hsum and hsum devices Flag: android.net.vcn.enforce_main_user Change-Id: I5abfa7ba82055cd953083b1ab3f83e61bafd8a55 --- Vcn/flags/flags.aconfig | 10 +++++ .../android/server/VcnManagementService.java | 20 +++++++++- .../server/VcnManagementServiceTest.java | 37 ++++++++++++------- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 6fde398528..0469b7fcb2 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -36,6 +36,16 @@ flag{ bug: "323238888" } +flag{ + name: "enforce_main_user" + namespace: "vcn" + description: "Enforce main user to make VCN HSUM compatible" + bug: "310310661" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag{ name: "handle_seq_num_leap" namespace: "vcn" diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 7acca19f9d..e2b6bd6ae3 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -36,6 +36,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -47,6 +48,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.vcn.Flags; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -68,6 +70,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; +import android.os.UserManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -431,6 +434,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { mTelephonySubscriptionTracker.register(); } + // The system server automatically has the required permissions for #getMainUser() + @SuppressLint("AndroidFrameworkRequiresPermission") private void enforcePrimaryUser() { final int uid = mDeps.getBinderCallingUid(); if (uid == Process.SYSTEM_UID) { @@ -438,7 +443,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Calling identity was System Server. Was Binder calling identity cleared?"); } - if (!UserHandle.getUserHandleForUid(uid).isSystem()) { + final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); + + if (Flags.enforceMainUser()) { + final UserManager userManager = mContext.getSystemService(UserManager.class); + + Binder.withCleanCallingIdentity( + () -> { + if (!Objects.equals(userManager.getMainUser(), userHandle)) { + throw new SecurityException( + "VcnManagementService can only be used by callers running as" + + " the main user"); + } + }); + } else if (!userHandle.isSystem()) { throw new SecurityException( "VcnManagementService can only be used by callers running as the primary user"); } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 960b57cb63..580efe126e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -70,6 +70,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; +import android.net.vcn.Flags; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -82,7 +83,9 @@ import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.Process; import android.os.UserHandle; +import android.os.UserManager; import android.os.test.TestLooper; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -101,6 +104,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -118,6 +122,8 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); @@ -129,7 +135,12 @@ public class VcnManagementServiceTest { private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2)); private static final VcnConfig TEST_VCN_CONFIG; private static final VcnConfig TEST_VCN_CONFIG_PKG_2; - private static final int TEST_UID = Process.FIRST_APPLICATION_UID; + + private static final int TEST_UID = 1010000; // A non-system user + private static final UserHandle TEST_USER_HANDLE = UserHandle.getUserHandleForUid(TEST_UID); + private static final UserHandle TEST_USER_HANDLE_OTHER = + UserHandle.of(TEST_USER_HANDLE.getIdentifier() + 1); + private static final String TEST_IFACE_NAME = "TEST_IFACE"; private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2"; private static final LinkProperties TEST_LP_1 = new LinkProperties(); @@ -187,6 +198,7 @@ public class VcnManagementServiceTest { private final TelephonyManager mTelMgr = mock(TelephonyManager.class); private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class); private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class); + private final UserManager mUserManager = mock(UserManager.class); private final VcnContext mVcnContext = mock(VcnContext.class); private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper = mock(PersistableBundleUtils.LockingReadWriteHelper.class); @@ -218,6 +230,9 @@ public class VcnManagementServiceTest { Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class); setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); + setupSystemService(mMockContext, mUserManager, Context.USER_SERVICE, UserManager.class); + + doReturn(TEST_USER_HANDLE).when(mUserManager).getMainUser(); doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName(); @@ -267,6 +282,8 @@ public class VcnManagementServiceTest { @Before public void setUp() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENFORCE_MAIN_USER); + doNothing() .when(mMockContext) .enforceCallingOrSelfPermission( @@ -717,10 +734,8 @@ public class VcnManagementServiceTest { } @Test - public void testSetVcnConfigRequiresSystemUser() throws Exception { - doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) - .when(mMockDeps) - .getBinderCallingUid(); + public void testSetVcnConfigRequiresMainUser() throws Exception { + doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser(); try { mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -832,10 +847,8 @@ public class VcnManagementServiceTest { } @Test - public void testClearVcnConfigRequiresSystemUser() throws Exception { - doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) - .when(mMockDeps) - .getBinderCallingUid(); + public void testClearVcnConfigRequiresMainUser() throws Exception { + doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser(); try { mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); @@ -921,10 +934,8 @@ public class VcnManagementServiceTest { } @Test - public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception { - doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID)) - .when(mMockDeps) - .getBinderCallingUid(); + public void testGetConfiguredSubscriptionGroupsRequiresMainUser() throws Exception { + doReturn(TEST_USER_HANDLE_OTHER).when(mUserManager).getMainUser(); try { mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); From d0535d420a56f5b747ede3665d6ca9e8313779e3 Mon Sep 17 00:00:00 2001 From: bkchoi Date: Mon, 22 Jul 2024 14:01:22 -0700 Subject: [PATCH 0441/1057] Enable secondary_user_on_secondary_display for CtsVcnTestCases --secondary_user_on_secondary_display is for background users that have UI access on assigned displays, a.k.a. visible background users, on devices that have config_multiuserVisibleBackgroundUsers enabled. The main use case is Automotive's multi-display where passengers (modeled as visible background users) can interact with the display in front of them concurrently with the driver (modeled as the the current user) who interacts with driver's display. Bug: 354264548 Test: atest --user-type secondary_user_on_secondary_display \ CtsVcnTestCases Test: atest CtsVcnTestCases Change-Id: I5bee41272175af5e440889af4061b2c6cfbff919 --- Vcn/tests/cts/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Vcn/tests/cts/AndroidTest.xml b/Vcn/tests/cts/AndroidTest.xml index 286a671d5b..d4ccba6cf6 100644 --- a/Vcn/tests/cts/AndroidTest.xml +++ b/Vcn/tests/cts/AndroidTest.xml @@ -19,6 +19,7 @@

    This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN + * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN + * Gateway. + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder setMinUdpPort4500NatTimeoutSeconds( + @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) + int minUdpPort4500NatTimeoutSeconds) { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s"); + + mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; + return Builder.this; + } + + /** Build a VcnTransportInfo instance */ + @NonNull + public VcnTransportInfo build() { + return new VcnTransportInfo( + null /* wifiInfo */, INVALID_SUBSCRIPTION_ID, mMinUdpPort4500NatTimeoutSeconds); + } + } } diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUtils.java b/Vcn/framework-b/src/android/net/vcn/VcnUtils.java new file mode 100644 index 0000000000..6dc5180977 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnUtils.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn; + +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.net.TransportInfo; +import android.net.wifi.WifiInfo; + +import java.util.List; + +/** + * Utility class for VCN callers get information from VCN network + * + * @hide + */ +public class VcnUtils { + /** Get the WifiInfo of the VCN's underlying WiFi network */ + @Nullable + public static WifiInfo getWifiInfoFromVcnCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + final NetworkCapabilities underlyingCaps = + getVcnUnderlyingCaps(connectivityMgr, networkCapabilities); + + if (underlyingCaps == null) { + return null; + } + + final TransportInfo underlyingTransportInfo = underlyingCaps.getTransportInfo(); + if (!(underlyingTransportInfo instanceof WifiInfo)) { + return null; + } + + return (WifiInfo) underlyingTransportInfo; + } + + /** Get the subscription ID of the VCN's underlying Cell network */ + public static int getSubIdFromVcnCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + final NetworkCapabilities underlyingCaps = + getVcnUnderlyingCaps(connectivityMgr, networkCapabilities); + + if (underlyingCaps == null) { + return INVALID_SUBSCRIPTION_ID; + } + + final NetworkSpecifier underlyingNetworkSpecifier = underlyingCaps.getNetworkSpecifier(); + if (!(underlyingNetworkSpecifier instanceof TelephonyNetworkSpecifier)) { + return INVALID_SUBSCRIPTION_ID; + } + + return ((TelephonyNetworkSpecifier) underlyingNetworkSpecifier).getSubscriptionId(); + } + + @Nullable + private static NetworkCapabilities getVcnUnderlyingCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + // Return null if it is not a VCN network + if (networkCapabilities.getTransportInfo() == null + || !(networkCapabilities.getTransportInfo() instanceof VcnTransportInfo)) { + return null; + } + + // As of Android 16, VCN has one underlying network, and only one. If there are more + // than one networks due to future changes in the VCN mainline code, just take the first + // network + final List underlyingNws = networkCapabilities.getUnderlyingNetworks(); + if (underlyingNws == null) { + return null; + } + + return connectivityMgr.getNetworkCapabilities(underlyingNws.get(0)); + } +} diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java index 81814b67f5..7bc9970629 100644 --- a/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/VcnTransportInfoTest.java @@ -25,6 +25,7 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import android.net.NetworkCapabilities; import android.net.wifi.WifiConfiguration; @@ -39,6 +40,7 @@ public class VcnTransportInfoTest { private static final int SUB_ID = 1; private static final int NETWORK_ID = 5; private static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120; + private static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_INVALID = 119; private static final WifiInfo WIFI_INFO = new WifiInfo.Builder().setNetworkId(NETWORK_ID).build(); @@ -47,6 +49,27 @@ public class VcnTransportInfoTest { private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO, MIN_UDP_PORT_4500_NAT_TIMEOUT); + @Test + public void testBuilder() { + final VcnTransportInfo transportInfo = + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT) + .build(); + + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, transportInfo.getMinUdpPort4500NatTimeoutSeconds()); + } + + @Test + public void testBuilder_withInvalidNatTimeout() { + try { + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT_INVALID); + fail("Expected to fail due to invalid NAT timeout"); + } catch (Exception expected) { + } + } + @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); diff --git a/Vcn/tests/unit/java/android/net/vcn/VcnUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/VcnUtilsTest.java new file mode 100644 index 0000000000..3ce6c8f938 --- /dev/null +++ b/Vcn/tests/unit/java/android/net/vcn/VcnUtilsTest.java @@ -0,0 +1,136 @@ +/* + * 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 android.net.vcn; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.net.wifi.WifiInfo; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; + +public class VcnUtilsTest { + private static final int SUB_ID = 1; + + private static final WifiInfo WIFI_INFO = new WifiInfo.Builder().build(); + private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); + private static final VcnTransportInfo VCN_TRANSPORT_INFO = + new VcnTransportInfo.Builder().build(); + + private ConnectivityManager mMockConnectivityManager; + private Network mMockWifiNetwork; + private Network mMockCellNetwork; + + private NetworkCapabilities mVcnCapsWithUnderlyingWifi; + private NetworkCapabilities mVcnCapsWithUnderlyingCell; + + @Before + public void setUp() { + mMockConnectivityManager = mock(ConnectivityManager.class); + + mMockWifiNetwork = mock(Network.class); + mVcnCapsWithUnderlyingWifi = newVcnCaps(VCN_TRANSPORT_INFO, mMockWifiNetwork); + final NetworkCapabilities wifiCaps = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .setTransportInfo(WIFI_INFO) + .build(); + when(mMockConnectivityManager.getNetworkCapabilities(mMockWifiNetwork)) + .thenReturn(wifiCaps); + + mMockCellNetwork = mock(Network.class); + mVcnCapsWithUnderlyingCell = newVcnCaps(VCN_TRANSPORT_INFO, mMockCellNetwork); + final NetworkCapabilities cellCaps = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .build(); + when(mMockConnectivityManager.getNetworkCapabilities(mMockCellNetwork)) + .thenReturn(cellCaps); + } + + private static NetworkCapabilities newVcnCaps( + VcnTransportInfo vcnTransportInfo, Network underlyingNetwork) { + return new NetworkCapabilities.Builder() + .setTransportInfo(vcnTransportInfo) + .setUnderlyingNetworks(Collections.singletonList(underlyingNetwork)) + .build(); + } + + @Test + public void getWifiInfoFromVcnCaps() { + assertEquals( + WIFI_INFO, + VcnUtils.getWifiInfoFromVcnCaps( + mMockConnectivityManager, mVcnCapsWithUnderlyingWifi)); + } + + @Test + public void getWifiInfoFromVcnCaps_onVcnWithUnderlyingCell() { + assertNull( + VcnUtils.getWifiInfoFromVcnCaps( + mMockConnectivityManager, mVcnCapsWithUnderlyingCell)); + } + + @Test + public void getSubIdFromVcnCaps() { + assertEquals( + SUB_ID, + VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, mVcnCapsWithUnderlyingCell)); + } + + @Test + public void getSubIdFromVcnCaps_onVcnWithUnderlyingWifi() { + assertEquals( + INVALID_SUBSCRIPTION_ID, + VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, mVcnCapsWithUnderlyingWifi)); + } + + @Test + public void getSubIdFromVcnCaps_onNonVcnNetwork() { + assertEquals( + INVALID_SUBSCRIPTION_ID, + VcnUtils.getSubIdFromVcnCaps( + mMockConnectivityManager, new NetworkCapabilities.Builder().build())); + } + + @Test + public void getSubIdFromVcnCaps_withMultipleUnderlyingNetworks() { + final NetworkCapabilities vcnCaps = + new NetworkCapabilities.Builder(mVcnCapsWithUnderlyingCell) + .setUnderlyingNetworks( + Arrays.asList( + new Network[] {mMockCellNetwork, mock(Network.class)})) + .build(); + assertEquals(SUB_ID, VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, vcnCaps)); + } +} From 87c094581de170cc02f8418a2ee922488c4bc237 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 10 Oct 2024 10:59:58 -0700 Subject: [PATCH 0458/1057] Clean up FLAG_HANDLE_SEQ_NUM_LEAP Bug: 332598276 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag clean up Change-Id: I3d0dd6251337d85a4c6f193d9a627e66024a79ab --- Vcn/flags/flags.aconfig | 10 ---------- .../vcn/routeselection/IpSecPacketLossDetector.java | 13 +++++-------- .../routeselection/NetworkEvaluationTestBase.java | 1 - 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index dcb363ccf5..77b5b77f44 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -45,14 +45,4 @@ flag{ metadata { purpose: PURPOSE_BUGFIX } -} - -flag{ - name: "handle_seq_num_leap" - namespace: "vcn" - description: "Do not report bad network when there is a suspected sequence number leap" - bug: "332598276" - metadata { - purpose: PURPOSE_BUGFIX - } } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 5f704a002a..c351d92e91 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -233,7 +233,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { @VisibleForTesting(visibility = Visibility.PRIVATE) static int getMaxSeqNumIncreasePerSecond(@Nullable PersistableBundleWrapper carrierConfig) { int maxSeqNumIncrease = MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED; - if (Flags.handleSeqNumLeap() && carrierConfig != null) { + if (carrierConfig != null) { maxSeqNumIncrease = carrierConfig.getInt( VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY, @@ -287,10 +287,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // with the new interval mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); - if (Flags.handleSeqNumLeap()) { - mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); - mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); - } + mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); if (canStart() != isStarted()) { if (canStart()) { @@ -474,8 +472,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { boolean isUnusualSeqNumLeap = false; // Handle sequence number leap - if (Flags.handleSeqNumLeap() - && maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { + if (maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { final long timeDiffMillis = newState.getTimestampMillis() - oldState.getTimestampMillis(); final long maxSeqNumIncrease = timeDiffMillis * maxSeqNumIncreasePerSecond / 1000; @@ -506,7 +503,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { + " actualPktCntDiff: " + actualPktCntDiff); - if (Flags.handleSeqNumLeap() && expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) { + if (expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) { // The sample size is too small to ensure a reliable detection result return PacketLossCalculationResult.invalid(); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index edad67896e..97617f9abc 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -122,7 +122,6 @@ public abstract class NetworkEvaluationTestBase { mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); - mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP); when(mNetwork.getNetId()).thenReturn(-1); From 06dc8ecb9377c32b83459372bd3b169b2e3bf92c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 10 Oct 2024 11:08:22 -0700 Subject: [PATCH 0459/1057] Clean up FLAG_ENFORCE_MAIN_USER Bug: 310310661 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag cleanup Change-Id: I461c4167397608fffbf366c90e4d3bb42e2564f5 --- Vcn/flags/flags.aconfig | 10 -------- .../android/server/VcnManagementService.java | 25 +++++++------------ .../server/VcnManagementServiceTest.java | 7 ------ 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 77b5b77f44..15d671dde0 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -35,14 +35,4 @@ flag{ namespace: "vcn" description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change" bug: "323238888" -} - -flag{ - name: "enforce_main_user" - namespace: "vcn" - description: "Enforce main user to make VCN HSUM compatible" - bug: "310310661" - metadata { - purpose: PURPOSE_BUGFIX - } } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 12e8c57228..947f6b73d3 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -48,7 +48,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.vcn.Flags; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -447,22 +446,16 @@ public class VcnManagementService extends IVcnManagementService.Stub { } final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); + final UserManager userManager = mContext.getSystemService(UserManager.class); - if (Flags.enforceMainUser()) { - final UserManager userManager = mContext.getSystemService(UserManager.class); - - Binder.withCleanCallingIdentity( - () -> { - if (!Objects.equals(userManager.getMainUser(), userHandle)) { - throw new SecurityException( - "VcnManagementService can only be used by callers running as" - + " the main user"); - } - }); - } else if (!userHandle.isSystem()) { - throw new SecurityException( - "VcnManagementService can only be used by callers running as the primary user"); - } + Binder.withCleanCallingIdentity( + () -> { + if (!Objects.equals(userManager.getMainUser(), userHandle)) { + throw new SecurityException( + "VcnManagementService can only be used by callers running as" + + " the main user"); + } + }); } private void enforceCallingUserAndCarrierPrivilege( diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4cb7c91b24..7e0bbc4b3e 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -70,7 +70,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; -import android.net.vcn.Flags; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -85,7 +84,6 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; -import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -104,7 +102,6 @@ import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -122,8 +119,6 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); @@ -285,8 +280,6 @@ public class VcnManagementServiceTest { @Before public void setUp() { - mSetFlagsRule.enableFlags(Flags.FLAG_ENFORCE_MAIN_USER); - doNothing() .when(mMockContext) .enforceCallingOrSelfPermission( From aa3971b14ca3fc78129e9f969889e86e45fc4b63 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 10 Oct 2024 11:53:55 -0700 Subject: [PATCH 0460/1057] Clean up FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE Bug: 323238888 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag cleanup Change-Id: I18a6c5b32806b6cd20bfa6b5b475d220be975a7c --- Vcn/flags/flags.aconfig | 7 ------- .../routeselection/UnderlyingNetworkEvaluator.java | 13 ++++--------- .../routeselection/NetworkEvaluationTestBase.java | 1 - 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 15d671dde0..614c7634af 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -28,11 +28,4 @@ flag{ namespace: "vcn" description: "Trigger network validation when IPsec packet loss exceeds the threshold" bug: "329139898" -} - -flag{ - name: "evaluate_ipsec_loss_on_lp_nc_change" - namespace: "vcn" - description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change" - bug: "323238888" } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 78e06d46c7..c852fb4e17 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -25,7 +25,6 @@ import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.vcn.Flags; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; @@ -297,10 +296,8 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); - if (Flags.evaluateIpsecLossOnLpNcChange()) { - for (NetworkMetricMonitor monitor : mMetricMonitors) { - monitor.onLinkPropertiesOrCapabilitiesChanged(); - } + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.onLinkPropertiesOrCapabilitiesChanged(); } } @@ -316,10 +313,8 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); - if (Flags.evaluateIpsecLossOnLpNcChange()) { - for (NetworkMetricMonitor monitor : mMetricMonitors) { - monitor.onLinkPropertiesOrCapabilitiesChanged(); - } + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.onLinkPropertiesOrCapabilitiesChanged(); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 97617f9abc..2320dfc224 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -121,7 +121,6 @@ public abstract class NetworkEvaluationTestBase { MockitoAnnotations.initMocks(this); mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); - mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); when(mNetwork.getNetId()).thenReturn(-1); From 56c0b9f0ec65e73a69beb32e89a3d46c5b857250 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 10 Oct 2024 12:13:18 -0700 Subject: [PATCH 0461/1057] Clean up FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS This CL also fixes incorrect code comments Bug: 329139898 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag cleanup Change-Id: Ib61dfbf9c3e147766530dbc519a785b8b13fac9d --- Vcn/flags/flags.aconfig | 7 ------- .../vcn/routeselection/IpSecPacketLossDetector.java | 12 ++++-------- .../routeselection/NetworkEvaluationTestBase.java | 7 ------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 614c7634af..efddd1f9fc 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -21,11 +21,4 @@ flag{ namespace: "vcn" description: "Feature flag for enabling network metric monitor" bug: "282996138" -} - -flag{ - name: "validate_network_on_ipsec_loss" - namespace: "vcn" - description: "Trigger network validation when IPsec packet loss exceeds the threshold" - bug: "329139898" } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index c351d92e91..6f1e15b503 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -29,7 +29,6 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.IpSecTransformState; import android.net.Network; -import android.net.vcn.Flags; import android.net.vcn.VcnManager; import android.os.Handler; import android.os.HandlerExecutor; @@ -436,13 +435,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { onValidationResultReceivedInternal(true /* isFailed */); } - // In both "valid" or "unusual_seq_num_leap" cases, trigger network validation - if (Flags.validateNetworkOnIpsecLoss()) { - // Trigger re-validation of the underlying network; if it fails, the VCN will - // attempt to migrate away. - mConnectivityManager.reportNetworkConnectivity( - getNetwork(), false /* hasConnectivity */); - } + // In both "invalid" and "unusual_seq_num_leap" cases, trigger network validation. If + // validation fails, the VCN will attempt to migrate away. + mConnectivityManager.reportNetworkConnectivity( + getNetwork(), false /* hasConnectivity */); } } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 2320dfc224..421e1ad20b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -34,14 +34,12 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.FeatureFlags; -import android.net.vcn.Flags; import android.os.Handler; import android.os.IPowerManager; import android.os.IThermalService; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; -import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.TelephonyManager; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -49,7 +47,6 @@ import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; import org.junit.Before; -import org.junit.Rule; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -57,8 +54,6 @@ import java.util.Set; import java.util.UUID; public abstract class NetworkEvaluationTestBase { - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - protected static final String SSID = "TestWifi"; protected static final String SSID_OTHER = "TestWifiOther"; protected static final String PLMN_ID = "123456"; @@ -120,8 +115,6 @@ public abstract class NetworkEvaluationTestBase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); - when(mNetwork.getNetId()).thenReturn(-1); mTestLooper = new TestLooper(); From 09ee2711980b995a9a5400b3fb2ef5b474d603c1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 12 Oct 2024 00:29:20 +0000 Subject: [PATCH 0462/1057] Create VCN folder This is a preparation CL to decouple VCN from the platform code. It follow the steps suggested by go/mainline-onboarding-in-trunk-stable. Eventually VCN will be moved to Tethering module. Followup CLs will migrate all VCN source code to this folder and thus VCN will not automatically be built into the framework.jar and services.jar anymore. Bug: 369703242 Test: build and boot Flag: EXEMPT no functional change Change-Id: I41484406ab88a8910a87f8df9e53199731c0ce08 --- Vcn/OWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Vcn/OWNERS diff --git a/Vcn/OWNERS b/Vcn/OWNERS new file mode 100644 index 0000000000..ff2146e76b --- /dev/null +++ b/Vcn/OWNERS @@ -0,0 +1,6 @@ +evitayan@google.com +nharold@google.com +benedictwong@google.com #{LAST_RESORT_SUGGESTION} +yangji@google.com #{LAST_RESORT_SUGGESTION} + +include platform/packages/modules/common:/MODULES_OWNERS \ No newline at end of file From 746edebefc1e941a69c75879aaecd470f1eafe86 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 00:18:25 +0000 Subject: [PATCH 0463/1057] Register VcnManager with VcnFrameworkInitializer When VCN is moved out of framework.jar, SystemServiceRegistry will not be able to register VCN service via IVcnManagementService anymore because the aidl interface will not be accessible. To solve this issue, this CL follows go/android-api-guidelines#the-moduleframeworkinitializer-pattern to create an FrameworkInitializer for service registration. Followup CLs will expose this class as @SystemApi. Bug: 369703242 Test: atest CtsVcnTestCases Flag: EXEMPT code refactoring; no functional change Change-Id: Ic9668a60f195f0a21de5114c1bb0bc38b72ee4d5 --- .../net/vcn/VcnFrameworkInitializer.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java new file mode 100644 index 0000000000..8cb213b306 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn; + +import android.annotation.Nullable; +import android.app.SystemServiceRegistry; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.SystemProperties; + +/** + * Class for performing registration for VCN service. + * + * @hide + */ +// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) +public final class VcnFrameworkInitializer { + /** + * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers + * that depend on them. If the feature is missing, {@link Context#getSystemService} will return + * null. + * + *

    This change is specific to VcnManager. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + /** + * The corresponding vendor API for Android V + * + *

    Starting with Android V, the vendor API format has switched to YYYYMM. + * + * @see Vendor API + * level + */ + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + + private VcnFrameworkInitializer() {} + + // Suppressing AndroidFrameworkCompatChange because we're querying vendor + // partition SDK level, not application's target SDK version (which BTW we + // also check through Compatibility framework a few lines below). + @Nullable + private static String getVcnFeatureDependency() { + // Check SDK version of the client app. Apps targeting pre-V SDK might + // have not checked for existence of these features. + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + return null; + } + + // Check SDK version of the vendor partition. Pre-V devices might have + // incorrectly under-declared telephony features. + final int vendorApiLevel = + SystemProperties.getInt( + "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); + if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { + return PackageManager.FEATURE_TELEPHONY; + } else { + return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + } + } + + /** + * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return + * a VcnManager. + * + * @throws IllegalStateException if this is called anywhere besides {@link + * SystemServiceRegistry}. + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + VcnManager.VCN_MANAGEMENT_SERVICE_STRING, + VcnManager.class, + (context, serviceBinder) -> { + final String telephonyFeatureToCheck = getVcnFeatureDependency(); + if (telephonyFeatureToCheck != null + && !context.getPackageManager() + .hasSystemFeature(telephonyFeatureToCheck)) { + return null; + } + IVcnManagementService service = + IVcnManagementService.Stub.asInterface(serviceBinder); + return new VcnManager(context, service); + }); + } +} From 133d92eb2c8a0cd40e9b0e5601e5aeb6ee01f179 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 16 Oct 2024 19:09:42 -0700 Subject: [PATCH 0464/1057] Clean up flag network_metric_monitor Bug: 282996138 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag clean up Change-Id: I300d9c391d0aeb26ca6a589960244641de76ac1b --- Vcn/flags/flags.aconfig | 7 ------- .../src/com/android/server/vcn/VcnContext.java | 4 ---- .../android/server/vcn/VcnGatewayConnection.java | 1 - .../vcn/routeselection/NetworkMetricMonitor.java | 6 ------ .../UnderlyingNetworkController.java | 15 +++++---------- .../UnderlyingNetworkEvaluator.java | 3 +-- .../server/vcn/VcnGatewayConnectionTestBase.java | 1 - .../routeselection/NetworkEvaluationTestBase.java | 1 - .../UnderlyingNetworkControllerTest.java | 1 - 9 files changed, 6 insertions(+), 33 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index efddd1f9fc..5b306243fc 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -14,11 +14,4 @@ flag { namespace: "vcn" description: "Feature flag for adjustable safe mode timeout" bug: "317406085" -} - -flag{ - name: "network_metric_monitor" - namespace: "vcn" - description: "Feature flag for enabling network metric monitor" - bug: "282996138" } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 6a4c9c26d3..a492a72933 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -70,10 +70,6 @@ public class VcnContext { return mIsInTestMode; } - public boolean isFlagNetworkMetricMonitorEnabled() { - return mFeatureFlags.networkMetricMonitor(); - } - public boolean isFlagIpSecTransformStateEnabled() { // TODO: b/328844044: Ideally this code should gate the behavior by checking the // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index b574782834..a81ad22ddf 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1913,7 +1913,6 @@ public class VcnGatewayConnection extends StateMachine { mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); if (direction == IpSecManager.DIRECTION_IN - && mVcnContext.isFlagNetworkMetricMonitorEnabled() && mVcnContext.isFlagIpSecTransformStateEnabled()) { mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform); } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index b9b10606a1..0d4c373677 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -62,12 +62,6 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { @Nullable PersistableBundleWrapper carrierConfig, @NonNull NetworkMetricMonitorCallback callback) throws IllegalAccessException { - if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) { - // Caller error - logWtf("networkMetricMonitor flag disabled"); - throw new IllegalAccessException("networkMetricMonitor flag disabled"); - } - mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mNetwork = Objects.requireNonNull(network, "Missing network"); mCallback = Objects.requireNonNull(callback, "Missing callback"); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 2b0ca08023..ad5bc7294f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -204,8 +204,7 @@ public class UnderlyingNetworkController { List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); - if (mVcnContext.isFlagNetworkMetricMonitorEnabled() - && mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (mVcnContext.isFlagIpSecTransformStateEnabled()) { for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { evaluator.close(); } @@ -431,8 +430,7 @@ public class UnderlyingNetworkController { .getAllSubIdsInGroup(mSubscriptionGroup) .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { - if (mVcnContext.isFlagNetworkMetricMonitorEnabled() - && mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (mVcnContext.isFlagIpSecTransformStateEnabled()) { reevaluateNetworks(); } return; @@ -447,8 +445,7 @@ public class UnderlyingNetworkController { */ public void updateInboundTransform( @NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) { - if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() - || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { logWtf("#updateInboundTransform: unexpected call; flags missing"); return; } @@ -575,8 +572,7 @@ public class UnderlyingNetworkController { @Override public void onLost(@NonNull Network network) { - if (mVcnContext.isFlagNetworkMetricMonitorEnabled() - && mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (mVcnContext.isFlagIpSecTransformStateEnabled()) { mUnderlyingNetworkRecords.get(network).close(); } @@ -652,8 +648,7 @@ public class UnderlyingNetworkController { class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback { @Override public void onEvaluationResultChanged() { - if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() - || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { logWtf("#onEvaluationResultChanged: unexpected call; flags missing"); return; } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index c852fb4e17..53b0751d19 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -193,8 +193,7 @@ public class UnderlyingNetworkEvaluator { } private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) { - return vcnContext.isFlagIpSecTransformStateEnabled() - && vcnContext.isFlagNetworkMetricMonitorEnabled(); + return vcnContext.isFlagIpSecTransformStateEnabled(); } /** Get the comparator for UnderlyingNetworkEvaluator */ diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index e29e4621d5..e045f100e5 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -224,7 +224,6 @@ public class VcnGatewayConnectionTestBase { doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); - doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index 421e1ad20b..bc7ff47d9a 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -127,7 +127,6 @@ public abstract class NetworkEvaluationTestBase { false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); setupSystemService( diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 588624b562..6f31d8db07 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -226,7 +226,6 @@ public class UnderlyingNetworkControllerTest { private void resetVcnContext(VcnContext vcnContext) { reset(vcnContext); doNothing().when(vcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(vcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled(); } From 05b7cfba4337517c883011fcb5023db33d02d3a9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 17 Oct 2024 12:45:50 -0700 Subject: [PATCH 0465/1057] Remove @RequiresFlagsEnabled annotations for released flags Bug: 317406085 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT test code Change-Id: I938fb18fb26819abe0c246d0dc2eb9c7ffb46b1d --- .../net/vcn/cts/VcnGatewayConnectionConfigTest.java | 10 ---------- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 99d0c2ef47..12b9adb4d8 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -29,16 +29,11 @@ import static org.junit.Assert.fail; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; -import android.net.vcn.Flags; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,9 +45,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnGatewayConnectionConfigTest extends VcnTestBase { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; private static final long[] RETRY_INTERNAL_MILLIS = new long[] { @@ -191,7 +183,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { } } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) @Test public void testBuilderSetSafeModeEnabled() { final VcnGatewayConnectionConfig gatewayConnConfig = @@ -199,7 +190,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { assertFalse(gatewayConnConfig.isSafeModeEnabled()); } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) @Test public void testGetSafeModeEnabledDefault() { final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfig(); diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 7d13fea0b2..81630ffe6d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -66,7 +66,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.vcn.Flags; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; @@ -79,9 +78,6 @@ import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.Capabilitie import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.SystemClock; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -94,7 +90,6 @@ import com.android.compatibility.common.util.CarrierPrivilegeUtils; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -113,9 +108,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnManagerTest extends VcnTestBase { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; @@ -1341,7 +1333,6 @@ public class VcnManagerTest extends VcnTestBase { verifyVcnSafeModeTimeoutOnTestNetwork(subId, SAFEMODE_TIMEOUT_MILLIS); } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG) @Test public void testVcnSafeModeOnTestNetwork_overrideTimeout() throws Exception { final int subId = verifyAndGetValidDataSubId(); @@ -1409,14 +1400,12 @@ public class VcnManagerTest extends VcnTestBase { .build(); } - @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) @Test public void testEnterSafeModeImmediately_safeModeEnabled() throws Exception { verifyEnterSafeModeImmediately( newVcnConfig(true /* isSafeModeEnabled */), true /* isSafeModeExpected */); } - @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_CONFIG, Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) @Test public void testEnterSafeModeImmediately_safeModeDisabled() throws Exception { verifyEnterSafeModeImmediately( From 69bdb450f904ad3e29aa7563db9bef79a65d7dd5 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 00:18:25 +0000 Subject: [PATCH 0466/1057] Register VcnManager with VcnFrameworkInitializer When VCN is moved out of framework.jar, SystemServiceRegistry will not be able to register VCN service via IVcnManagementService anymore because the aidl interface will not be accessible. To solve this issue, this CL follows go/android-api-guidelines#the-moduleframeworkinitializer-pattern to create an FrameworkInitializer for service registration. Followup CLs will expose this class as @SystemApi. Bug: 369703242 Test: atest CtsVcnTestCases Flag: EXEMPT code refactoring; no functional change Change-Id: Ic9668a60f195f0a21de5114c1bb0bc38b72ee4d5 Merged-In: Ic9668a60f195f0a21de5114c1bb0bc38b72ee4d5 --- .../net/vcn/VcnFrameworkInitializer.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java new file mode 100644 index 0000000000..8cb213b306 --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn; + +import android.annotation.Nullable; +import android.app.SystemServiceRegistry; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.SystemProperties; + +/** + * Class for performing registration for VCN service. + * + * @hide + */ +// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) +public final class VcnFrameworkInitializer { + /** + * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers + * that depend on them. If the feature is missing, {@link Context#getSystemService} will return + * null. + * + *

    This change is specific to VcnManager. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + /** + * The corresponding vendor API for Android V + * + *

    Starting with Android V, the vendor API format has switched to YYYYMM. + * + * @see Vendor API + * level + */ + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + + private VcnFrameworkInitializer() {} + + // Suppressing AndroidFrameworkCompatChange because we're querying vendor + // partition SDK level, not application's target SDK version (which BTW we + // also check through Compatibility framework a few lines below). + @Nullable + private static String getVcnFeatureDependency() { + // Check SDK version of the client app. Apps targeting pre-V SDK might + // have not checked for existence of these features. + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + return null; + } + + // Check SDK version of the vendor partition. Pre-V devices might have + // incorrectly under-declared telephony features. + final int vendorApiLevel = + SystemProperties.getInt( + "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); + if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { + return PackageManager.FEATURE_TELEPHONY; + } else { + return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + } + } + + /** + * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return + * a VcnManager. + * + * @throws IllegalStateException if this is called anywhere besides {@link + * SystemServiceRegistry}. + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + VcnManager.VCN_MANAGEMENT_SERVICE_STRING, + VcnManager.class, + (context, serviceBinder) -> { + final String telephonyFeatureToCheck = getVcnFeatureDependency(); + if (telephonyFeatureToCheck != null + && !context.getPackageManager() + .hasSystemFeature(telephonyFeatureToCheck)) { + return null; + } + IVcnManagementService service = + IVcnManagementService.Stub.asInterface(serviceBinder); + return new VcnManager(context, service); + }); + } +} From abb90bf8cdcccbf121dbf4decfd8ec382f03b53d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 2 Oct 2024 17:26:55 -0700 Subject: [PATCH 0467/1057] Replace utility classes This commit replaces utility classes that will no longer be accessible after VCN moves out of the platform Bug: 369703242 Test: atest CtsVcnTestCases && atest FrameworksVcnTests Flag: EXEMPT code refactoring; no functional change Change-Id: Ia5c987c25728a1ef6ac4aeda02e1c9339c2a3af9 --- .../vcn/VcnCellUnderlyingNetworkTemplate.java | 2 +- .../src/android/net/vcn/VcnManager.java | 8 +++---- .../net/vcn/VcnUnderlyingNetworkTemplate.java | 2 +- .../vcn/VcnWifiUnderlyingNetworkTemplate.java | 2 +- .../android/server/VcnManagementService.java | 23 ++++++++++--------- .../vcn/TelephonySubscriptionTracker.java | 2 +- .../src/com/android/server/vcn/Vcn.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 2 +- .../server/vcn/VcnNetworkProvider.java | 2 +- .../UnderlyingNetworkController.java | 2 +- .../UnderlyingNetworkEvaluator.java | 2 +- .../UnderlyingNetworkRecord.java | 2 +- 12 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 46cf0163c0..c0398ce1fc 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -40,9 +40,9 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index 1c9be6fb4b..f275714e2c 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -28,13 +28,13 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; -import android.os.Binder; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceSpecificException; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.net.module.util.BinderUtils; import java.io.IOException; import java.lang.annotation.Retention; @@ -711,7 +711,7 @@ public class VcnManager { @Override public void onPolicyChanged() { - Binder.withCleanCallingIdentity( + BinderUtils.withCleanCallingIdentity( () -> mExecutor.execute(() -> mListener.onPolicyChanged())); } } @@ -734,7 +734,7 @@ public class VcnManager { @Override public void onVcnStatusChanged(@VcnStatusCode int statusCode) { - Binder.withCleanCallingIdentity( + BinderUtils.withCleanCallingIdentity( () -> mExecutor.execute(() -> mCallback.onStatusChanged(statusCode))); } @@ -747,7 +747,7 @@ public class VcnManager { @Nullable String exceptionMessage) { final Throwable cause = createThrowableByClassName(exceptionClass, exceptionMessage); - Binder.withCleanCallingIdentity( + BinderUtils.withCleanCallingIdentity( () -> mExecutor.execute( () -> diff --git a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java index edf2c093bc..16114dd135 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -21,10 +21,10 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.PersistableBundle; +import android.util.IndentingPrintWriter; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 2e6b09f032..c7b2f188ba 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -29,9 +29,9 @@ import android.net.NetworkCapabilities; import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 947f6b73d3..51c768b80e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -75,6 +75,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Log; import android.util.Slog; @@ -82,7 +83,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.BinderUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -448,7 +449,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); final UserManager userManager = mContext.getSystemService(UserManager.class); - Binder.withCleanCallingIdentity( + BinderUtils.withCleanCallingIdentity( () -> { if (!Objects.equals(userManager.getMainUser(), userHandle)) { throw new SecurityException( @@ -468,7 +469,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // TODO (b/172619301): Check based on events propagated from CarrierPrivilegesTracker final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); final List subscriptionInfos = new ArrayList<>(); - Binder.withCleanCallingIdentity( + BinderUtils.withCleanCallingIdentity( () -> { List subsInGroup = subMgr.getSubscriptionsInGroup(subscriptionGroup); @@ -700,7 +701,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void notifyAllPolicyListenersLocked() { for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) { - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { try { policyListener.mListener.onPolicyChanged(); } catch (RemoteException e) { @@ -715,7 +716,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, subGroup)) { - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { try { cbInfo.mCallback.onVcnStatusChanged(statusCode); } catch (RemoteException e) { @@ -795,7 +796,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { enforceManageTestNetworksForTestMode(config); enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { synchronized (mLock) { mConfigs.put(subscriptionGroup, config); startOrUpdateVcnLocked(subscriptionGroup, config); @@ -853,7 +854,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { .checkPackage(mDeps.getBinderCallingUid(), opPkgName); enforceCarrierPrivilegeOrProvisioningPackage(subscriptionGroup, opPkgName); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { synchronized (mLock) { stopAndClearVcnConfigInternalLocked(subscriptionGroup); writeConfigsToDiskLocked(); @@ -991,7 +992,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { android.Manifest.permission.NETWORK_FACTORY, android.Manifest.permission.MANAGE_TEST_NETWORKS); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); synchronized (mLock) { @@ -1018,7 +1019,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { android.Manifest.permission.NETWORK_FACTORY, android.Manifest.permission.MANAGE_TEST_NETWORKS); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { synchronized (mLock) { PolicyListenerBinderDeath listenerBinderDeath = mRegisteredPolicyListeners.remove(listener.asBinder()); @@ -1082,7 +1083,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { + " MANAGE_TEST_NETWORKS"); } - return Binder.withCleanCallingIdentity(() -> { + return BinderUtils.withCleanCallingIdentity(() -> { // Defensive copy in case this call is in-process and the given NetworkCapabilities // mutates final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities); @@ -1521,7 +1522,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, mSubGroup)) { - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { try { cbInfo.mCallback.onGatewayConnectionError( gatewayConnectionName, diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 1e82b89998..baf84cf4aa 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -40,11 +40,11 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.util.ArrayList; diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 5bc2c2dfac..1fba29779f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -47,11 +47,11 @@ import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.util.LogUtils; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index a81ad22ddf..189b608918 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -90,11 +90,11 @@ import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 31ee2477fa..78ff432f54 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -36,11 +36,11 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import java.util.Objects; import java.util.Set; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index ad5bc7294f..0b9b677df1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -46,11 +46,11 @@ import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 53b0751d19..448a7ebfff 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -29,11 +29,11 @@ import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.os.Handler; import android.os.ParcelUuid; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index 7ab8e55272..1945052b92 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -22,10 +22,10 @@ import android.annotation.Nullable; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.internal.util.IndentingPrintWriter; import java.util.Objects; From ed640aa2cd485cc800e082cad75fb7ff677e6dc8 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 25 Oct 2024 11:55:01 -0700 Subject: [PATCH 0468/1057] Add VCN tests to postsubmit This patch is to fulfil the prerequisite for adding these tests to presubmit in this TEST_MAPPING file, as per go/test-mapping-slo-guide. It also adds postsubmit coverage for future VCN changes. Bug: 369703242 Test: build Flag: EXEMPT TEST_MAPPING change Change-Id: I83c9034b56e7a6de458f26b8a4f01df08f355e87 --- Vcn/TEST_MAPPING | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Vcn/TEST_MAPPING diff --git a/Vcn/TEST_MAPPING b/Vcn/TEST_MAPPING new file mode 100644 index 0000000000..bde88fe9b7 --- /dev/null +++ b/Vcn/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "postsubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } + ] +} \ No newline at end of file From 191868d9b0a5ea5673764259e0376be82e24b1f3 Mon Sep 17 00:00:00 2001 From: "gang.huang" Date: Tue, 29 Oct 2024 16:27:48 +0800 Subject: [PATCH 0469/1057] Ignore null action in VcnManagementService$VcnBroadcastReceiver Bug: 376183723 Test: Manual. Change-Id: I079421b080942eb49db0c2aeb09e2c75378a0c3b --- Vcn/service-b/src/com/android/server/VcnManagementService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 51c768b80e..4a94edbddf 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -524,6 +524,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); + if (action == null) { + return; + } switch (action) { case Intent.ACTION_PACKAGE_ADDED: // Fallthrough From 2d63da828409c28a663d7493346158c37918e8cf Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 29 Oct 2024 23:13:44 +0000 Subject: [PATCH 0470/1057] Update VCN OWNERS files Bug: NA Test: build Flag: EXEMPT; OWNERS file change Change-Id: I2463752b75165ebb0acc472a20ca79d381b9c66e --- Vcn/framework-b/src/android/net/vcn/OWNERS | 5 ++--- Vcn/service-b/src/com/android/server/vcn/OWNERS | 5 ++--- Vcn/tests/unit/OWNERS | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/OWNERS b/Vcn/framework-b/src/android/net/vcn/OWNERS index 2441e77246..937699a929 100644 --- a/Vcn/framework-b/src/android/net/vcn/OWNERS +++ b/Vcn/framework-b/src/android/net/vcn/OWNERS @@ -1,7 +1,6 @@ set noparent -benedictwong@google.com -ckesting@google.com evitayan@google.com -junyin@google.com nharold@google.com +benedictwong@google.com #{LAST_RESORT_SUGGESTION} +yangji@google.com #{LAST_RESORT_SUGGESTION} diff --git a/Vcn/service-b/src/com/android/server/vcn/OWNERS b/Vcn/service-b/src/com/android/server/vcn/OWNERS index 2441e77246..937699a929 100644 --- a/Vcn/service-b/src/com/android/server/vcn/OWNERS +++ b/Vcn/service-b/src/com/android/server/vcn/OWNERS @@ -1,7 +1,6 @@ set noparent -benedictwong@google.com -ckesting@google.com evitayan@google.com -junyin@google.com nharold@google.com +benedictwong@google.com #{LAST_RESORT_SUGGESTION} +yangji@google.com #{LAST_RESORT_SUGGESTION} diff --git a/Vcn/tests/unit/OWNERS b/Vcn/tests/unit/OWNERS index 2441e77246..937699a929 100644 --- a/Vcn/tests/unit/OWNERS +++ b/Vcn/tests/unit/OWNERS @@ -1,7 +1,6 @@ set noparent -benedictwong@google.com -ckesting@google.com evitayan@google.com -junyin@google.com nharold@google.com +benedictwong@google.com #{LAST_RESORT_SUGGESTION} +yangji@google.com #{LAST_RESORT_SUGGESTION} From c03d453cf27ed716786d4d0ec46a8fb92ba9ead7 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 29 Oct 2024 23:35:52 +0000 Subject: [PATCH 0471/1057] Add a flag to control the exposure of VCN APIs for mainline migration Bug: 369703242 Test: build Flag: android.net.vcn.mainline_vcn_module_api Change-Id: I728275a90b0dea8add60631e034ec081a07f23d7 --- Vcn/flags/flags.aconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 5b306243fc..2966e8a15f 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -9,6 +9,14 @@ flag { bug: "276358140" } +flag { + name: "mainline_vcn_module_api" + namespace: "vcn" + description: "Expose APIs from VCN for mainline migration" + is_exported: true + bug: "376339506" +} + flag { name: "safe_mode_timeout_config" namespace: "vcn" From a2284ca391717fc41376a657e12e1ff60ed1a31d Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 28 Oct 2024 13:43:34 -0700 Subject: [PATCH 0472/1057] Fix VcnConfig garbage collection The garbageCollectAndWriteVcnConfigsLocked is for removing configs whose subgroups do not have any subscriptions. This patch fixes the issue of it in handling race condition when subscription changes. Previously the garbage collection checks a subGroup's subscriptions based on SubscriptionManager. When SubscriptionManager and TelephonySubscriptionSnapshot are out-of-synced, the config of an active VCN instance will be removed. It can cause NPE in getUnderlyingNetworkPolicy. This patch fixes it by checking subscriptions against the snapshot. This patch also fixes the safety check in getUnderlyingNetworkPolicy so that if VCN instance exists but its config does not, it will not attempt querying data from the VcnConfig Bug: 370862489 Test: FrameworksVcnTests(new tests); CtsVcnTestCases Flag: android.net.vcn.fix_config_garbage_collection Change-Id: Id54adabcc1910102a2ab20c432b693a8f52c5c95 --- Vcn/flags/flags.aconfig | 10 +++++ .../android/server/VcnManagementService.java | 31 ++++++++++------ .../vcn/TelephonySubscriptionTracker.java | 11 ++++++ .../server/VcnManagementServiceTest.java | 37 +++++++++++++++++++ 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 5b306243fc..3d4401b1c7 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -14,4 +14,14 @@ flag { namespace: "vcn" description: "Feature flag for adjustable safe mode timeout" bug: "317406085" +} + +flag { + name: "fix_config_garbage_collection" + namespace: "vcn" + description: "Handle race condition in subscription change" + bug: "370862489" + metadata { + purpose: PURPOSE_BUGFIX + } } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 51c768b80e..dc7749cb02 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -48,6 +48,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.vcn.Flags; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -878,6 +879,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { private void garbageCollectAndWriteVcnConfigsLocked() { final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); + final Set subGroups = mLastSnapshot.getAllSubscriptionGroups(); boolean shouldWrite = false; @@ -885,11 +887,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { while (configsIterator.hasNext()) { final ParcelUuid subGrp = configsIterator.next(); - final List subscriptions = subMgr.getSubscriptionsInGroup(subGrp); - if (subscriptions == null || subscriptions.isEmpty()) { - // Trim subGrps with no more subscriptions; must have moved to another subGrp - configsIterator.remove(); - shouldWrite = true; + if (Flags.fixConfigGarbageCollection()) { + if (!subGroups.contains(subGrp)) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + logDbg("Garbage collect VcnConfig for group=" + subGrp); + configsIterator.remove(); + shouldWrite = true; + } + } else { + final List subscriptions = subMgr.getSubscriptionsInGroup(subGrp); + if (subscriptions == null || subscriptions.isEmpty()) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + configsIterator.remove(); + shouldWrite = true; + } } } @@ -1094,13 +1105,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final Vcn vcn = mVcns.get(subGrp); final VcnConfig vcnConfig = mConfigs.get(subGrp); - if (vcn != null) { - if (vcnConfig == null) { - // TODO: b/284381334 Investigate for the root cause of this issue - // and handle it properly - logWtf("Vcn instance exists but VcnConfig does not for " + subGrp); - } - + if (vcn != null && vcnConfig != null) { if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) { isVcnManagedNetwork = true; } @@ -1120,6 +1125,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } } + } else if (vcn != null && vcnConfig == null) { + logWtf("Vcn instance exists but VcnConfig does not for " + subGrp); } } diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index baf84cf4aa..3392d03910 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -436,6 +436,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return mPrivilegedPackages.keySet(); } + /** Returns all subscription groups */ + @NonNull + public Set getAllSubscriptionGroups() { + final Set subGroups = new ArraySet<>(); + for (SubscriptionInfo subInfo : mSubIdToInfoMap.values()) { + subGroups.add(subInfo.getGroupUuid()); + } + + return subGroups; + } + /** Checks if the provided package is carrier privileged for the specified sub group. */ public boolean packageHasPermissionsForSubscriptionGroup( @NonNull ParcelUuid subGrp, @NonNull String packageName) { diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 7e0bbc4b3e..3828a71d7b 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -70,6 +70,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; +import android.net.vcn.Flags; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -84,6 +85,7 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -102,6 +104,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -119,6 +122,8 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) @SmallTest public class VcnManagementServiceTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); @@ -288,6 +293,8 @@ public class VcnManagementServiceTest { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) .getRestrictedTransports(any(), any(), any()); + + mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CONFIG_GARBAGE_COLLECTION); } @@ -438,6 +445,14 @@ public class VcnManagementServiceTest { return subIds; }).when(snapshot).getAllSubIdsInGroup(any()); + doAnswer(invocation -> { + final Set subGroups = new ArraySet<>(); + for (Entry entry : subIdToGroupMap.entrySet()) { + subGroups.add(entry.getValue()); + } + return subGroups; + }).when(snapshot).getAllSubscriptionGroups(); + return snapshot; } @@ -1482,6 +1497,28 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testGarbageCollectionKeepConfigUntilNewSnapshot() throws Exception { + setupActiveSubscription(TEST_UUID_2); + startAndGetVcnInstance(TEST_UUID_2); + + // Report loss of subscription from mSubMgr + doReturn(Collections.emptyList()).when(mSubMgr).getSubscriptionsInGroup(any()); + triggerSubscriptionTrackerCbAndGetSnapshot( + TEST_UUID_2, + Collections.singleton(TEST_UUID_2), + Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); + + assertTrue(mVcnMgmtSvc.getConfigs().containsKey(TEST_UUID_2)); + + // Report loss of subscription from snapshot + triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); + + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + assertFalse(mVcnMgmtSvc.getConfigs().containsKey(TEST_UUID_2)); + } + @Test public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception { setupActiveSubscription(TEST_UUID_2); From f0a2597ba350b3a8de35ba778209904813a06040 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 17 Oct 2024 12:59:31 -0700 Subject: [PATCH 0473/1057] Clean up flag ipsec_transform_state Bug: 308011229 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag clean up Change-Id: I1ebbdbbd5e4d9e17fe05bba8d9d75ffbb7c79699 --- .../com/android/server/vcn/VcnContext.java | 14 -------- .../server/vcn/VcnGatewayConnection.java | 3 +- .../IpSecPacketLossDetector.java | 6 ---- .../UnderlyingNetworkController.java | 26 +++----------- .../UnderlyingNetworkEvaluator.java | 36 +++++++------------ .../vcn/VcnGatewayConnectionTestBase.java | 1 - .../NetworkEvaluationTestBase.java | 3 -- .../UnderlyingNetworkControllerTest.java | 1 - 8 files changed, 17 insertions(+), 73 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index a492a72933..6ce8685400 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -18,7 +18,6 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; -import android.net.IpSecTransformState; import android.net.vcn.FeatureFlags; import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; @@ -70,19 +69,6 @@ public class VcnContext { return mIsInTestMode; } - public boolean isFlagIpSecTransformStateEnabled() { - // TODO: b/328844044: Ideally this code should gate the behavior by checking the - // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible - // right now. We should either update the code when the flag is accessible or remove the - // legacy behavior after VIC SDK finalization - try { - new IpSecTransformState.Builder(); - return true; - } catch (Exception e) { - return false; - } - } - @NonNull public FeatureFlags getFeatureFlags() { return mFeatureFlags; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 189b608918..2d3bc84deb 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1912,8 +1912,7 @@ public class VcnGatewayConnection extends StateMachine { // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); - if (direction == IpSecManager.DIRECTION_IN - && mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (direction == IpSecManager.DIRECTION_IN) { mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform); } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 6f1e15b503..16ab51e8d6 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -148,12 +148,6 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { Objects.requireNonNull(deps, "Missing deps"); - if (!vcnContext.isFlagIpSecTransformStateEnabled()) { - // Caller error - logWtf("ipsecTransformState flag disabled"); - throw new IllegalAccessException("ipsecTransformState flag disabled"); - } - mHandler = new Handler(getVcnContext().getLooper()); mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 0b9b677df1..3eeeece5da 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -204,10 +204,8 @@ public class UnderlyingNetworkController { List oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { - evaluator.close(); - } + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.close(); } mUnderlyingNetworkRecords.clear(); @@ -429,10 +427,7 @@ public class UnderlyingNetworkController { if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { - - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - reevaluateNetworks(); - } + reevaluateNetworks(); return; } registerOrUpdateNetworkRequests(); @@ -445,11 +440,6 @@ public class UnderlyingNetworkController { */ public void updateInboundTransform( @NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) { - if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { - logWtf("#updateInboundTransform: unexpected call; flags missing"); - return; - } - Objects.requireNonNull(currentNetwork, "currentNetwork is null"); Objects.requireNonNull(transform, "transform is null"); @@ -572,10 +562,7 @@ public class UnderlyingNetworkController { @Override public void onLost(@NonNull Network network) { - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - mUnderlyingNetworkRecords.get(network).close(); - } - + mUnderlyingNetworkRecords.get(network).close(); mUnderlyingNetworkRecords.remove(network); reevaluateNetworks(); @@ -648,11 +635,6 @@ public class UnderlyingNetworkController { class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback { @Override public void onEvaluationResultChanged() { - if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { - logWtf("#onEvaluationResultChanged: unexpected call; flags missing"); - return; - } - mVcnContext.ensureRunningOnLooperThread(); reevaluateNetworks(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 448a7ebfff..08be11e296 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -102,17 +102,15 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); - if (isIpSecPacketLossDetectorEnabled()) { - try { - mMetricMonitors.add( - mDependencies.newIpSecPacketLossDetector( - mVcnContext, - mNetworkRecordBuilder.getNetwork(), - carrierConfig, - new MetricMonitorCallbackImpl())); - } catch (IllegalAccessException e) { - // No action. Do not add anything to mMetricMonitors - } + try { + mMetricMonitors.add( + mDependencies.newIpSecPacketLossDetector( + mVcnContext, + mNetworkRecordBuilder.getNetwork(), + carrierConfig, + new MetricMonitorCallbackImpl())); + } catch (IllegalAccessException e) { + // No action. Do not add anything to mMetricMonitors } } @@ -188,22 +186,12 @@ public class UnderlyingNetworkEvaluator { } } - private boolean isIpSecPacketLossDetectorEnabled() { - return isIpSecPacketLossDetectorEnabled(mVcnContext); - } - - private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) { - return vcnContext.isFlagIpSecTransformStateEnabled(); - } - /** Get the comparator for UnderlyingNetworkEvaluator */ public static Comparator getComparator(VcnContext vcnContext) { return (left, right) -> { - if (isIpSecPacketLossDetectorEnabled(vcnContext)) { - if (left.mIsPenalized != right.mIsPenalized) { - // A penalized network should have lower priority which means a larger index - return left.mIsPenalized ? 1 : -1; - } + if (left.mIsPenalized != right.mIsPenalized) { + // A penalized network should have lower priority which means a larger index + return left.mIsPenalized ? 1 : -1; } final int leftIndex = left.mPriorityClass; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index e045f100e5..4c7b25aaa7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -223,7 +223,6 @@ public class VcnGatewayConnectionTestBase { doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); - doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index bc7ff47d9a..441b780357 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -20,7 +20,6 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -127,8 +126,6 @@ public abstract class NetworkEvaluationTestBase { false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); - setupSystemService( mContext, mConnectivityManager, diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 6f31d8db07..e540932d0e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -226,7 +226,6 @@ public class UnderlyingNetworkControllerTest { private void resetVcnContext(VcnContext vcnContext) { reset(vcnContext); doNothing().when(vcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled(); } // Package private for use in NetworkPriorityClassifierTest From 2860fd1bbf7faac95aa9cfc9b5dae66b8b1b6f23 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 17 Oct 2024 12:41:22 -0700 Subject: [PATCH 0474/1057] Clean up flag safe_mode_timeout_config Bug: 317406085 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT flag clean up Change-Id: I2f838156ffa9a2242747f4782e4d05833674e393 --- Vcn/flags/flags.aconfig | 7 ------- .../com/android/server/vcn/VcnContext.java | 4 ---- .../server/vcn/VcnGatewayConnection.java | 2 +- .../server/vcn/VcnGatewayConnectionTest.java | 19 ++----------------- .../vcn/VcnGatewayConnectionTestBase.java | 1 - 5 files changed, 3 insertions(+), 30 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 1adefe5a0b..1b2c575917 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -17,13 +17,6 @@ flag { bug: "376339506" } -flag { - name: "safe_mode_timeout_config" - namespace: "vcn" - description: "Feature flag for adjustable safe mode timeout" - bug: "317406085" -} - flag { name: "fix_config_garbage_collection" namespace: "vcn" diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java index 6ce8685400..9213d96ad4 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnContext.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnContext.java @@ -74,10 +74,6 @@ public class VcnContext { return mFeatureFlags; } - public boolean isFlagSafeModeTimeoutConfigEnabled() { - return mFeatureFlags.safeModeTimeoutConfig(); - } - /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 2d3bc84deb..2325f358e3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1263,7 +1263,7 @@ public class VcnGatewayConnection extends StateMachine { final PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp); int resultSeconds = defaultSeconds; - if (vcnContext.isFlagSafeModeTimeoutConfigEnabled() && carrierConfig != null) { + if (carrierConfig != null) { resultSeconds = carrierConfig.getInt( VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, defaultSeconds); diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 49665f7a33..613b926167 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -360,12 +360,10 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private void verifyGetSafeModeTimeoutMs( boolean isInTestMode, - boolean isConfigTimeoutSupported, PersistableBundleWrapper carrierConfig, long expectedTimeoutMs) throws Exception { doReturn(isInTestMode).when(mVcnContext).isInTestMode(); - doReturn(isConfigTimeoutSupported).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(carrierConfig).when(snapshot).getCarrierConfigForSubGrp(TEST_SUB_GRP); @@ -377,16 +375,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } @Test - public void testGetSafeModeTimeoutMs_configTimeoutUnsupported() throws Exception { - verifyGetSafeModeTimeoutMs( - false /* isInTestMode */, - false /* isConfigTimeoutSupported */, - null /* carrierConfig */, - TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); - } - - @Test - public void testGetSafeModeTimeoutMs_configTimeoutSupported() throws Exception { + public void testGetSafeModeTimeoutMs() throws Exception { final int carrierConfigTimeoutSeconds = 20; final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); doReturn(carrierConfigTimeoutSeconds) @@ -395,17 +384,14 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyGetSafeModeTimeoutMs( false /* isInTestMode */, - true /* isConfigTimeoutSupported */, carrierConfig, TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); } @Test - public void testGetSafeModeTimeoutMs_configTimeoutSupported_carrierConfigNull() - throws Exception { + public void testGetSafeModeTimeoutMs_carrierConfigNull() throws Exception { verifyGetSafeModeTimeoutMs( false /* isInTestMode */, - true /* isConfigTimeoutSupported */, null /* carrierConfig */, TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); } @@ -420,7 +406,6 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyGetSafeModeTimeoutMs( true /* isInTestMode */, - true /* isConfigTimeoutSupported */, carrierConfig, TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 4c7b25aaa7..8374fd9445 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -222,7 +222,6 @@ public class VcnGatewayConnectionTestBase { doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); - doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) From 754c007883c7c025fabb5ff5ad5baf4faf95b368 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Sat, 21 Sep 2024 01:09:17 +0000 Subject: [PATCH 0475/1057] Create empty VCN libraries This is a prepartion CL to move VCN to its own libraries and eventually migrate it from the non-updatable platform to Tethering module. This CL creates a new VCN directory with an empty java_sdk_library and an empty java_library. In followup CLs, VCN source code will be migrated to this VCN folder. VCN framework code and system server code will be built into the two libraries. Bug: 369703242 Test: build and boot Flag: EXEMPT create new empty libraries; no functional change Change-Id: I0f2e02771ac81a3d3fd588a6199be888ae299e52 --- Vcn/framework-b/Android.bp | 44 +++++++++++++++++++ Vcn/framework-b/api/current.txt | 1 + Vcn/framework-b/api/module-lib-current.txt | 1 + Vcn/framework-b/api/module-lib-removed.txt | 1 + Vcn/framework-b/api/removed.txt | 1 + Vcn/framework-b/api/system-current.txt | 1 + Vcn/framework-b/api/system-removed.txt | 1 + .../src/android/net/vcn/Placeholder.java | 25 +++++++++++ Vcn/service-b/Android.bp | 36 +++++++++++++++ .../com/android/server/vcn/Placeholder.java | 25 +++++++++++ 10 files changed, 136 insertions(+) create mode 100644 Vcn/framework-b/Android.bp create mode 100644 Vcn/framework-b/api/current.txt create mode 100644 Vcn/framework-b/api/module-lib-current.txt create mode 100644 Vcn/framework-b/api/module-lib-removed.txt create mode 100644 Vcn/framework-b/api/removed.txt create mode 100644 Vcn/framework-b/api/system-current.txt create mode 100644 Vcn/framework-b/api/system-removed.txt create mode 100644 Vcn/framework-b/src/android/net/vcn/Placeholder.java create mode 100644 Vcn/service-b/Android.bp create mode 100644 Vcn/service-b/src/com/android/server/vcn/Placeholder.java diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp new file mode 100644 index 0000000000..be64bb1ae4 --- /dev/null +++ b/Vcn/framework-b/Android.bp @@ -0,0 +1,44 @@ +// +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_enigma", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_defaults { + name: "framework-connectivity-b-defaults", + sdk_version: "module_current", + min_sdk_version: "35", // TODO: Make it Android 25Q2 when this is included in mainline + defaults: ["framework-module-defaults"], // This is a boot jar + + srcs: [ + "src/**/*.java", + ], +} + +java_sdk_library { + name: "framework-connectivity-b", + defaults: [ + "framework-connectivity-b-defaults", + ], + + permitted_packages: [ + "android.net.vcn", + ], + + // TODO: b/375213246 Expose this library to Tethering module +} diff --git a/Vcn/framework-b/api/current.txt b/Vcn/framework-b/api/current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/api/module-lib-current.txt b/Vcn/framework-b/api/module-lib-current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/module-lib-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/api/module-lib-removed.txt b/Vcn/framework-b/api/module-lib-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/api/removed.txt b/Vcn/framework-b/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/api/system-current.txt b/Vcn/framework-b/api/system-current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/system-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/api/system-removed.txt b/Vcn/framework-b/api/system-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/Vcn/framework-b/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/Vcn/framework-b/src/android/net/vcn/Placeholder.java b/Vcn/framework-b/src/android/net/vcn/Placeholder.java new file mode 100644 index 0000000000..fb5e15386c --- /dev/null +++ b/Vcn/framework-b/src/android/net/vcn/Placeholder.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn; + +/** + * Placeholder class so new framework-vcn isn't empty + * + * @hide + */ +// This class will be removed once source code is migrated +public class Placeholder {} diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp new file mode 100644 index 0000000000..a462297c07 --- /dev/null +++ b/Vcn/service-b/Android.bp @@ -0,0 +1,36 @@ +// +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_enigma", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_library { + name: "service-connectivity-b-pre-jarjar", + sdk_version: "system_server_current", + min_sdk_version: "35", // TODO: Make it Android 25Q2 when this is included in mainline + defaults: ["framework-system-server-module-defaults"], // This is a system server jar + + srcs: [ + "src/**/*.java", + ], + + // TODO: b/375213246 Expose this library to Tethering module + visibility: [ + "//frameworks/base/services", + ], +} diff --git a/Vcn/service-b/src/com/android/server/vcn/Placeholder.java b/Vcn/service-b/src/com/android/server/vcn/Placeholder.java new file mode 100644 index 0000000000..e79914531c --- /dev/null +++ b/Vcn/service-b/src/com/android/server/vcn/Placeholder.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn; + +/** + * Placeholder class so new service-vcn isn't empty + * + * @hide + */ +// This class will be removed once source code is migrated +public class Placeholder {} From 5a7cd59b4c8f2218898a9ba3b50517c7b8627806 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0476/1057] Expose VCN APIs for framework code As the first step of mainlining VCN, VCN will be moved from framework to its own java_sdk_library and hidden APIs will no longer be accessible to framework code. This CL exposes these classes, methods and constants as @SystemApi so that framework code can continue accessing them. Note, these APIs are temporarily exposed from framework.jar. Followup CLs will move them to the framework-connectivity-b.jar Bug: 376339506 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: android.net.vcn.mainline_vcn_module_api API-Coverage-Bug: 376553318 Change-Id: Ibf8a2d32ec3eae73cfb279dde2a0c74e4b4c5b33 --- .../net/vcn/VcnFrameworkInitializer.java | 106 ------------------ .../net/vcn/VcnGatewayConnectionConfig.java | 19 +++- .../src/android/net/vcn/VcnTransportInfo.java | 100 ++++++++++++++--- 3 files changed, 100 insertions(+), 125 deletions(-) delete mode 100644 Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java deleted file mode 100644 index 8cb213b306..0000000000 --- a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vcn; - -import android.annotation.Nullable; -import android.app.SystemServiceRegistry; -import android.compat.Compatibility; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.SystemProperties; - -/** - * Class for performing registration for VCN service. - * - * @hide - */ -// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) -public final class VcnFrameworkInitializer { - /** - * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link - * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers - * that depend on them. If the feature is missing, {@link Context#getSystemService} will return - * null. - * - *

    This change is specific to VcnManager. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) - private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; - - /** - * The corresponding vendor API for Android V - * - *

    Starting with Android V, the vendor API format has switched to YYYYMM. - * - * @see Vendor API - * level - */ - private static final int VENDOR_API_FOR_ANDROID_V = 202404; - - private VcnFrameworkInitializer() {} - - // Suppressing AndroidFrameworkCompatChange because we're querying vendor - // partition SDK level, not application's target SDK version (which BTW we - // also check through Compatibility framework a few lines below). - @Nullable - private static String getVcnFeatureDependency() { - // Check SDK version of the client app. Apps targeting pre-V SDK might - // have not checked for existence of these features. - if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { - return null; - } - - // Check SDK version of the vendor partition. Pre-V devices might have - // incorrectly under-declared telephony features. - final int vendorApiLevel = - SystemProperties.getInt( - "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); - if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { - return PackageManager.FEATURE_TELEPHONY; - } else { - return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; - } - } - - /** - * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return - * a VcnManager. - * - * @throws IllegalStateException if this is called anywhere besides {@link - * SystemServiceRegistry}. - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - VcnManager.VCN_MANAGEMENT_SERVICE_STRING, - VcnManager.class, - (context, serviceBinder) -> { - final String telephonyFeatureToCheck = getVcnFeatureDependency(); - if (telephonyFeatureToCheck != null - && !context.getPackageManager() - .hasSystemFeature(telephonyFeatureToCheck)) { - return null; - } - IVcnManagementService service = - IVcnManagementService.Stub.asInterface(serviceBinder); - return new VcnManager(context, service); - }); - } -} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index af93c964a8..3219ce81c2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; @@ -82,7 +83,15 @@ import java.util.concurrent.TimeUnit; * */ public final class VcnGatewayConnectionConfig { - /** @hide */ + /** + * Minimum NAT timeout not set. + * + *

    When the timeout is not set, the device will automatically choose a keepalive interval and + * may reduce the keepalive frequency for power-optimization. + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + // This constant does not represent a minimum value. It indicates the value is not configured. + @SuppressLint("MinMaxConstant") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; /** @hide */ @@ -773,7 +782,7 @@ public final class VcnGatewayConnectionConfig { * * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value. * @return this {@link Builder} instance, for chaining */ @NonNull @@ -781,8 +790,10 @@ public final class VcnGatewayConnectionConfig { @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 1fc91eea31..3638429f33 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -17,13 +17,16 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; @@ -52,23 +55,29 @@ import java.util.Objects; * @hide */ // TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore -public class VcnTransportInfo implements TransportInfo, Parcelable { +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; private final int mMinUdpPort4500NatTimeoutSeconds; + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds); } + /** @hide */ public VcnTransportInfo(int subId) { this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) { this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds); } @@ -86,6 +95,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { *

    If the underlying Network for the associated VCN is Cellular, returns null. * * @return the WifiInfo if there is an underlying WiFi connection, else null. + * @hide */ @Nullable public WifiInfo getWifiInfo() { @@ -100,17 +110,27 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * * @return the Subscription ID if a cellular underlying Network is present, else {@link * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * @hide */ public int getSubId() { return mSubId; } /** - * Get the VCN provided UDP port 4500 NAT timeout + * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * - * @return the UDP 4500 NAT timeout, or + *

    To ensure uninterrupted connectivity, the device must send keepalive packets before the + * timeout. Failure to do so may result in the mapping being cleared and connection termination. + * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or * VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set. + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public int getMinUdpPort4500NatTimeoutSeconds() { return mMinUdpPort4500NatTimeoutSeconds; } @@ -129,12 +149,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public int describeContents() { return 0; } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override @NonNull public TransportInfo makeCopy(long redactions) { @@ -149,6 +178,9 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { mMinUdpPort4500NatTimeoutSeconds); } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public long getApplicableRedactions() { long redactions = REDACT_FOR_NETWORK_SETTINGS; @@ -161,7 +193,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return redactions; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSubId); @@ -174,7 +212,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Creator CREATOR = new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { @@ -201,37 +245,63 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { } }; - /** This class can be used to construct a {@link VcnTransportInfo}. */ + /** + * This class can be used to construct a {@link VcnTransportInfo}. + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; - /** Construct Builder */ + /** + * Construct Builder + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public Builder() {} /** - * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * *

    This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. * - * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN - * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway + * guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} + * to clear this value. To ensure uninterrupted connectivity, the device must send + * keepalive packets within this interval. Failure to do so may result in the mapping + * being cleared and connection termination. * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return Builder.this; } - /** Build a VcnTransportInfo instance */ + /** + * Build a VcnTransportInfo instance + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public VcnTransportInfo build() { return new VcnTransportInfo( From bad9b8a6764295f2ace7cc1e3342b22d5635383b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 17 Oct 2024 12:45:50 -0700 Subject: [PATCH 0477/1057] Remove @RequiresFlagsEnabled annotations for released flags Bug: 317406085 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT test code Change-Id: I938fb18fb26819abe0c246d0dc2eb9c7ffb46b1d (cherry picked from commit 05b7cfba4337517c883011fcb5023db33d02d3a9) --- .../net/vcn/cts/VcnGatewayConnectionConfigTest.java | 10 ---------- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 99d0c2ef47..12b9adb4d8 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -29,16 +29,11 @@ import static org.junit.Assert.fail; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; -import android.net.vcn.Flags; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,9 +45,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnGatewayConnectionConfigTest extends VcnTestBase { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection"; private static final long[] RETRY_INTERNAL_MILLIS = new long[] { @@ -191,7 +183,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { } } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) @Test public void testBuilderSetSafeModeEnabled() { final VcnGatewayConnectionConfig gatewayConnConfig = @@ -199,7 +190,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { assertFalse(gatewayConnConfig.isSafeModeEnabled()); } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_CONFIG) @Test public void testGetSafeModeEnabledDefault() { final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfig(); diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 7d13fea0b2..81630ffe6d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -66,7 +66,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.vcn.Flags; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; @@ -79,9 +78,6 @@ import android.net.vcn.cts.TestNetworkWrapper.VcnTestNetworkCallback.Capabilitie import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.SystemClock; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -94,7 +90,6 @@ import com.android.compatibility.common.util.CarrierPrivilegeUtils; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -113,9 +108,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class VcnManagerTest extends VcnTestBase { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String TAG = VcnManagerTest.class.getSimpleName(); private static final int TIMEOUT_MS = 500; @@ -1341,7 +1333,6 @@ public class VcnManagerTest extends VcnTestBase { verifyVcnSafeModeTimeoutOnTestNetwork(subId, SAFEMODE_TIMEOUT_MILLIS); } - @RequiresFlagsEnabled(Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG) @Test public void testVcnSafeModeOnTestNetwork_overrideTimeout() throws Exception { final int subId = verifyAndGetValidDataSubId(); @@ -1409,14 +1400,12 @@ public class VcnManagerTest extends VcnTestBase { .build(); } - @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) @Test public void testEnterSafeModeImmediately_safeModeEnabled() throws Exception { verifyEnterSafeModeImmediately( newVcnConfig(true /* isSafeModeEnabled */), true /* isSafeModeExpected */); } - @RequiresFlagsEnabled({Flags.FLAG_SAFE_MODE_CONFIG, Flags.FLAG_SAFE_MODE_TIMEOUT_CONFIG}) @Test public void testEnterSafeModeImmediately_safeModeDisabled() throws Exception { verifyEnterSafeModeImmediately( From 637a20c83216e47f6d5779fcf8b357d64e70a725 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 13 Nov 2024 21:05:31 -0800 Subject: [PATCH 0478/1057] Include the "exported" flag lib in VCN CTS There will be a migration stage during VCN modularization where VCN flag host container is changed to tethering but VCN is still in the platform. At this stage, both VCN and CTS should access the flag via "exported" mode Bug: 376339506 Test: CtsVcnTestCases Flag: EXEMPT flag container value change Change-Id: I6a876c9d4b39c18613c7cf792ab44e29044bf47e --- Vcn/tests/cts/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 4114398a7f..2dde5fb970 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -40,7 +40,7 @@ android_test { "ike-tun-utils", "net-tests-utils", "telephony-cts-utils", - "android.net.vcn.flags-aconfig-java", + "android.net.vcn.flags-aconfig-java-export", "flag-junit", ], From 22c8d50056e662e7c126027b3d07584cbca39546 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0479/1057] Expose VCN APIs for framework code As the first step of mainlining VCN, VCN will be moved from framework to its own java_sdk_library and hidden APIs will no longer be accessible to framework code. This CL exposes these classes, methods and constants as @SystemApi so that framework code can continue accessing them. Note, these APIs are temporarily exposed from framework.jar. Followup CLs will move them to the framework-connectivity-b.jar Bug: 376339506 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: android.net.vcn.mainline_vcn_module_api API-Coverage-Bug: 376553318 Change-Id: Ibf8a2d32ec3eae73cfb279dde2a0c74e4b4c5b33 Merged-In: Ibf8a2d32ec3eae73cfb279dde2a0c74e4b4c5b33 --- .../net/vcn/VcnFrameworkInitializer.java | 106 ------------------ .../net/vcn/VcnGatewayConnectionConfig.java | 19 +++- .../src/android/net/vcn/VcnTransportInfo.java | 100 ++++++++++++++--- 3 files changed, 100 insertions(+), 125 deletions(-) delete mode 100644 Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java deleted file mode 100644 index 8cb213b306..0000000000 --- a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vcn; - -import android.annotation.Nullable; -import android.app.SystemServiceRegistry; -import android.compat.Compatibility; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.SystemProperties; - -/** - * Class for performing registration for VCN service. - * - * @hide - */ -// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) -public final class VcnFrameworkInitializer { - /** - * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link - * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers - * that depend on them. If the feature is missing, {@link Context#getSystemService} will return - * null. - * - *

    This change is specific to VcnManager. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) - private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; - - /** - * The corresponding vendor API for Android V - * - *

    Starting with Android V, the vendor API format has switched to YYYYMM. - * - * @see Vendor API - * level - */ - private static final int VENDOR_API_FOR_ANDROID_V = 202404; - - private VcnFrameworkInitializer() {} - - // Suppressing AndroidFrameworkCompatChange because we're querying vendor - // partition SDK level, not application's target SDK version (which BTW we - // also check through Compatibility framework a few lines below). - @Nullable - private static String getVcnFeatureDependency() { - // Check SDK version of the client app. Apps targeting pre-V SDK might - // have not checked for existence of these features. - if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { - return null; - } - - // Check SDK version of the vendor partition. Pre-V devices might have - // incorrectly under-declared telephony features. - final int vendorApiLevel = - SystemProperties.getInt( - "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); - if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { - return PackageManager.FEATURE_TELEPHONY; - } else { - return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; - } - } - - /** - * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return - * a VcnManager. - * - * @throws IllegalStateException if this is called anywhere besides {@link - * SystemServiceRegistry}. - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - VcnManager.VCN_MANAGEMENT_SERVICE_STRING, - VcnManager.class, - (context, serviceBinder) -> { - final String telephonyFeatureToCheck = getVcnFeatureDependency(); - if (telephonyFeatureToCheck != null - && !context.getPackageManager() - .hasSystemFeature(telephonyFeatureToCheck)) { - return null; - } - IVcnManagementService service = - IVcnManagementService.Stub.asInterface(serviceBinder); - return new VcnManager(context, service); - }); - } -} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index af93c964a8..3219ce81c2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; @@ -82,7 +83,15 @@ import java.util.concurrent.TimeUnit; * */ public final class VcnGatewayConnectionConfig { - /** @hide */ + /** + * Minimum NAT timeout not set. + * + *

    When the timeout is not set, the device will automatically choose a keepalive interval and + * may reduce the keepalive frequency for power-optimization. + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + // This constant does not represent a minimum value. It indicates the value is not configured. + @SuppressLint("MinMaxConstant") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; /** @hide */ @@ -773,7 +782,7 @@ public final class VcnGatewayConnectionConfig { * * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value. * @return this {@link Builder} instance, for chaining */ @NonNull @@ -781,8 +790,10 @@ public final class VcnGatewayConnectionConfig { @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 1fc91eea31..3638429f33 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -17,13 +17,16 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; @@ -52,23 +55,29 @@ import java.util.Objects; * @hide */ // TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore -public class VcnTransportInfo implements TransportInfo, Parcelable { +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; private final int mMinUdpPort4500NatTimeoutSeconds; + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds); } + /** @hide */ public VcnTransportInfo(int subId) { this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) { this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds); } @@ -86,6 +95,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { *

    If the underlying Network for the associated VCN is Cellular, returns null. * * @return the WifiInfo if there is an underlying WiFi connection, else null. + * @hide */ @Nullable public WifiInfo getWifiInfo() { @@ -100,17 +110,27 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * * @return the Subscription ID if a cellular underlying Network is present, else {@link * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * @hide */ public int getSubId() { return mSubId; } /** - * Get the VCN provided UDP port 4500 NAT timeout + * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * - * @return the UDP 4500 NAT timeout, or + *

    To ensure uninterrupted connectivity, the device must send keepalive packets before the + * timeout. Failure to do so may result in the mapping being cleared and connection termination. + * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or * VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set. + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public int getMinUdpPort4500NatTimeoutSeconds() { return mMinUdpPort4500NatTimeoutSeconds; } @@ -129,12 +149,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public int describeContents() { return 0; } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override @NonNull public TransportInfo makeCopy(long redactions) { @@ -149,6 +178,9 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { mMinUdpPort4500NatTimeoutSeconds); } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public long getApplicableRedactions() { long redactions = REDACT_FOR_NETWORK_SETTINGS; @@ -161,7 +193,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return redactions; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSubId); @@ -174,7 +212,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Creator CREATOR = new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { @@ -201,37 +245,63 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { } }; - /** This class can be used to construct a {@link VcnTransportInfo}. */ + /** + * This class can be used to construct a {@link VcnTransportInfo}. + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; - /** Construct Builder */ + /** + * Construct Builder + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public Builder() {} /** - * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * *

    This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. * - * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN - * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway + * guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} + * to clear this value. To ensure uninterrupted connectivity, the device must send + * keepalive packets within this interval. Failure to do so may result in the mapping + * being cleared and connection termination. * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return Builder.this; } - /** Build a VcnTransportInfo instance */ + /** + * Build a VcnTransportInfo instance + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public VcnTransportInfo build() { return new VcnTransportInfo( From 5f0f8fbe854b9aeef87fbab3c299ca0a362dad80 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 14 Nov 2024 05:51:51 -0800 Subject: [PATCH 0480/1057] Update VCN CTS to allow unset nat timeout With aosp/3291654, VCN now allows carrier apps to unset the NAT timeout. Bug: 376339506 Test: CtsVcnTestCases Flag: EXEMPT test code Change-Id: I703c81ad54186b53c36a9a02863233f96651e22a --- .../android/net/vcn/cts/VcnGatewayConnectionConfigTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 12b9adb4d8..618c3de743 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -170,12 +170,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { @Test public void testBuilderSetMinUdpPort4500NatTimeout_invalidValues() { - try { - buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(-1); - fail("Expected exception due to invalid timeout range"); - } catch (IllegalArgumentException e) { - } - try { buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(119); fail("Expected exception due to invalid timeout range"); From 4ce5fd1e9fdee6727c9b3e0c415fe93fa7c904ed Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0481/1057] Expose VCN APIs for framework code As the first step of mainlining VCN, VCN will be moved from framework to its own java_sdk_library and hidden APIs will no longer be accessible to framework code. This CL exposes these classes, methods and constants as @SystemApi so that framework code can continue accessing them. Note, these APIs are temporarily exposed from framework.jar. Followup CLs will move them to the framework-connectivity-b.jar Bug: 376339506 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: android.net.vcn.mainline_vcn_module_api API-Coverage-Bug: 376553318 Change-Id: Ibf8a2d32ec3eae73cfb279dde2a0c74e4b4c5b33 Merged-In: Ibf8a2d32ec3eae73cfb279dde2a0c74e4b4c5b33 (cherry picked from commit 5a7cd59b4c8f2218898a9ba3b50517c7b8627806) --- .../net/vcn/VcnFrameworkInitializer.java | 106 ------------------ .../net/vcn/VcnGatewayConnectionConfig.java | 19 +++- .../src/android/net/vcn/VcnTransportInfo.java | 100 ++++++++++++++--- 3 files changed, 100 insertions(+), 125 deletions(-) delete mode 100644 Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java diff --git a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java b/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java deleted file mode 100644 index 8cb213b306..0000000000 --- a/Vcn/framework-b/src/android/net/vcn/VcnFrameworkInitializer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vcn; - -import android.annotation.Nullable; -import android.app.SystemServiceRegistry; -import android.compat.Compatibility; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.SystemProperties; - -/** - * Class for performing registration for VCN service. - * - * @hide - */ -// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) -public final class VcnFrameworkInitializer { - /** - * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link - * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers - * that depend on them. If the feature is missing, {@link Context#getSystemService} will return - * null. - * - *

    This change is specific to VcnManager. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) - private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; - - /** - * The corresponding vendor API for Android V - * - *

    Starting with Android V, the vendor API format has switched to YYYYMM. - * - * @see Vendor API - * level - */ - private static final int VENDOR_API_FOR_ANDROID_V = 202404; - - private VcnFrameworkInitializer() {} - - // Suppressing AndroidFrameworkCompatChange because we're querying vendor - // partition SDK level, not application's target SDK version (which BTW we - // also check through Compatibility framework a few lines below). - @Nullable - private static String getVcnFeatureDependency() { - // Check SDK version of the client app. Apps targeting pre-V SDK might - // have not checked for existence of these features. - if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { - return null; - } - - // Check SDK version of the vendor partition. Pre-V devices might have - // incorrectly under-declared telephony features. - final int vendorApiLevel = - SystemProperties.getInt( - "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); - if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { - return PackageManager.FEATURE_TELEPHONY; - } else { - return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; - } - } - - /** - * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return - * a VcnManager. - * - * @throws IllegalStateException if this is called anywhere besides {@link - * SystemServiceRegistry}. - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - VcnManager.VCN_MANAGEMENT_SERVICE_STRING, - VcnManager.class, - (context, serviceBinder) -> { - final String telephonyFeatureToCheck = getVcnFeatureDependency(); - if (telephonyFeatureToCheck != null - && !context.getPackageManager() - .hasSystemFeature(telephonyFeatureToCheck)) { - return null; - } - IVcnManagementService service = - IVcnManagementService.Stub.asInterface(serviceBinder); - return new VcnManager(context, service); - }); - } -} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index af93c964a8..3219ce81c2 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; @@ -82,7 +83,15 @@ import java.util.concurrent.TimeUnit; * */ public final class VcnGatewayConnectionConfig { - /** @hide */ + /** + * Minimum NAT timeout not set. + * + *

    When the timeout is not set, the device will automatically choose a keepalive interval and + * may reduce the keepalive frequency for power-optimization. + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + // This constant does not represent a minimum value. It indicates the value is not configured. + @SuppressLint("MinMaxConstant") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; /** @hide */ @@ -773,7 +782,7 @@ public final class VcnGatewayConnectionConfig { * * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value. * @return this {@link Builder} instance, for chaining */ @NonNull @@ -781,8 +790,10 @@ public final class VcnGatewayConnectionConfig { @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 1fc91eea31..3638429f33 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -17,13 +17,16 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; @@ -52,23 +55,29 @@ import java.util.Objects; * @hide */ // TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore -public class VcnTransportInfo implements TransportInfo, Parcelable { +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; private final int mMinUdpPort4500NatTimeoutSeconds; + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds); } + /** @hide */ public VcnTransportInfo(int subId) { this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) { this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds); } @@ -86,6 +95,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { *

    If the underlying Network for the associated VCN is Cellular, returns null. * * @return the WifiInfo if there is an underlying WiFi connection, else null. + * @hide */ @Nullable public WifiInfo getWifiInfo() { @@ -100,17 +110,27 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * * @return the Subscription ID if a cellular underlying Network is present, else {@link * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * @hide */ public int getSubId() { return mSubId; } /** - * Get the VCN provided UDP port 4500 NAT timeout + * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * - * @return the UDP 4500 NAT timeout, or + *

    To ensure uninterrupted connectivity, the device must send keepalive packets before the + * timeout. Failure to do so may result in the mapping being cleared and connection termination. + * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or * VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set. + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public int getMinUdpPort4500NatTimeoutSeconds() { return mMinUdpPort4500NatTimeoutSeconds; } @@ -129,12 +149,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public int describeContents() { return 0; } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override @NonNull public TransportInfo makeCopy(long redactions) { @@ -149,6 +178,9 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { mMinUdpPort4500NatTimeoutSeconds); } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public long getApplicableRedactions() { long redactions = REDACT_FOR_NETWORK_SETTINGS; @@ -161,7 +193,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return redactions; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSubId); @@ -174,7 +212,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Creator CREATOR = new Creator() { public VcnTransportInfo createFromParcel(Parcel in) { @@ -201,37 +245,63 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { } }; - /** This class can be used to construct a {@link VcnTransportInfo}. */ + /** + * This class can be used to construct a {@link VcnTransportInfo}. + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; - /** Construct Builder */ + /** + * Construct Builder + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public Builder() {} /** - * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * *

    This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. * - * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN - * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway + * guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} + * to clear this value. To ensure uninterrupted connectivity, the device must send + * keepalive packets within this interval. Failure to do so may result in the mapping + * being cleared and connection termination. * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return Builder.this; } - /** Build a VcnTransportInfo instance */ + /** + * Build a VcnTransportInfo instance + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public VcnTransportInfo build() { return new VcnTransportInfo( From a940fde6529f3c786de956c637148f0c04fa16a4 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 13 Nov 2024 20:28:01 -0800 Subject: [PATCH 0482/1057] Clean up fix_config_garbage_collection To mainline VCN, we need to first change the VCN flag host container to be the tethering module and then use a buid flag to control whether to include VCN in the non-updatable platform or the module. After the container changes, when VCN is still in the platform, the VCN code can only access flags via "exported" mode, and only API flags are exportable and accessible. Thus the fix_config_garbage_collection flag needs to be handled It is safe to clean up this flag because it is a low risk bug fix and it has been in teamfood for a week with no issue being seen. Bug: 370862489 Test: FrameworksVcnTests; CtsVcnTestCases Flag: EXEMPT flag clean up Change-Id: If38b46735e7b20d918b7483c16b30101416b0a6c --- Vcn/flags/flags.aconfig | 10 ---------- .../android/server/VcnManagementService.java | 20 +++++-------------- .../server/VcnManagementServiceTest.java | 3 --- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index 1b2c575917..dc87866edb 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -15,14 +15,4 @@ flag { description: "Expose APIs from VCN for mainline migration" is_exported: true bug: "376339506" -} - -flag { - name: "fix_config_garbage_collection" - namespace: "vcn" - description: "Handle race condition in subscription change" - bug: "370862489" - metadata { - purpose: PURPOSE_BUGFIX - } } \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 06e6c8b1ec..2012f5632a 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -48,7 +48,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.vcn.Flags; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -890,20 +889,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { while (configsIterator.hasNext()) { final ParcelUuid subGrp = configsIterator.next(); - if (Flags.fixConfigGarbageCollection()) { - if (!subGroups.contains(subGrp)) { - // Trim subGrps with no more subscriptions; must have moved to another subGrp - logDbg("Garbage collect VcnConfig for group=" + subGrp); - configsIterator.remove(); - shouldWrite = true; - } - } else { - final List subscriptions = subMgr.getSubscriptionsInGroup(subGrp); - if (subscriptions == null || subscriptions.isEmpty()) { - // Trim subGrps with no more subscriptions; must have moved to another subGrp - configsIterator.remove(); - shouldWrite = true; - } + if (!subGroups.contains(subGrp)) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + logDbg("Garbage collect VcnConfig for group=" + subGrp); + configsIterator.remove(); + shouldWrite = true; } } diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 3828a71d7b..4ab8e6abbb 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -70,7 +70,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; -import android.net.vcn.Flags; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -293,8 +292,6 @@ public class VcnManagementServiceTest { doReturn(Collections.singleton(TRANSPORT_WIFI)) .when(mMockDeps) .getRestrictedTransports(any(), any(), any()); - - mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CONFIG_GARBAGE_COLLECTION); } From ce68d8c97f7977aa998c2fe29b309060dd354d9f Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 13 Nov 2024 16:37:03 +0000 Subject: [PATCH 0483/1057] Change VCN flag container to tethering VCN will be moved to Tetherig module eventually. This patch updates the VCN flag host container to the module and updates the framework.jar to access the flags via "exported" mode. Followup CLs will move VCN to a seperate java_sdk_library and the aconfig lib will be removed from framework-minus-apex-aconfig-declarations and moved to that java_sdk_library. A build system flag will control whether the VCN will be in platform or the tethering module. Bug: 376339506 Test: presubmit Flag: EXEMPT flag container value change Change-Id: I0434abce40dbadeec20f373f46484c41a08947ff --- Vcn/flags/flags.aconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vcn/flags/flags.aconfig b/Vcn/flags/flags.aconfig index dc87866edb..b461f95fec 100644 --- a/Vcn/flags/flags.aconfig +++ b/Vcn/flags/flags.aconfig @@ -1,5 +1,5 @@ package: "android.net.vcn" -container: "system" +container: "com.android.tethering" flag { name: "safe_mode_config" From 02cc3170d67dc120793c8f3e7696da080fde7301 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 20 Nov 2024 11:42:40 -0800 Subject: [PATCH 0484/1057] Only allow clearing NAT timeout when the 25Q2 flag is enabled This commit flags off the API behavior change that was meant to be added only to 25Q2, but was introduced to older SDKs and caused released CTS to fail. Bug: 379947714 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Test: verified against Android15 CTS Flag: android.net.vcn.mainline_vcn_module_api Change-Id: I39d33fa80225b138d64f18819eff07f5ef156dd1 --- .../net/vcn/VcnGatewayConnectionConfig.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index 3219ce81c2..b270062cbf 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -789,11 +789,17 @@ public final class VcnGatewayConnectionConfig { public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { - Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET - || minUdpPort4500NatTimeoutSeconds - >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); + if (Flags.mainlineVcnModuleApi()) { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); + } else { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s"); + } mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; From cc70bce0b811ec6e370b4873d3698d64d4615123 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 5 Nov 2024 23:54:17 +0000 Subject: [PATCH 0485/1057] Allow VCN CTS to access hidden VCN APIs Update VCN CTS to depend on VCN implementations so that it can continue accessing hidden VCN APIs like setIsTestModeProfile Bug: 369703242 Test: atest CtsVcnTestCases Flag: EXEMPT no functional change Change-Id: Ic10cbbc4ad1c552edcf5cfc153f0ad5fbe16c04d --- Vcn/tests/cts/Android.bp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 2dde5fb970..1756c5997a 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -19,7 +19,10 @@ package { android_test { name: "CtsVcnTestCases", - defaults: ["cts_defaults"], + defaults: [ + "cts_defaults", + "framework-connectivity-test-defaults", + ], // Include both the 32 and 64 bit versions compile_multilib: "both", @@ -47,6 +50,10 @@ android_test { platform_apis: true, // Tag this module as a cts test artifact + // TODO: b/375213246 Add "mcts-tethering" when VCN libs are + // built into Tethering module + // TODO: b/379938062 Move CtsVcnTestCases to the Tethering + // module folder (packages/modules/Connectivity) test_suites: [ "cts", "general-tests", From f8c2488f67e3c99acad4bbf98a1463debf459169 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 25 Oct 2024 14:40:14 -0700 Subject: [PATCH 0486/1057] Add VcnLocation to reflect the VCN build system flag value This patch defines VcnLocation.IS_VCN_IN_MAINLINE to reflect the value of the build system flag RELEASE_MOVE_VCN_TO_MAINLINE. Specifically two versions of VcnLocation file are defined. The build system flag controls which VcnLocation file will be built in to the platform. As results, the platform can read the value of IS_VCN_IN_MAINLINE to know the value of the build system flag. Bug: 375213246 Test: build-flag set RELEASE_MOVE_VCN_TO_MAINLINE and verified IS_VCN_IN_MAINLINE value Flag: RELEASE_MOVE_VCN_TO_MAINLINE Change-Id: I550fe1cc8a582b672281fd816804726a56531ca4 --- Vcn/service-b/Android.bp | 13 ++++++++ .../com/android/server/vcn/VcnLocation.java | 31 ++++++++++++++++++ .../com/android/server/vcn/VcnLocation.java | 32 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java create mode 100644 Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index a462297c07..03ef4e67af 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -19,6 +19,19 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +filegroup { + name: "vcn-location-sources", + srcs: select(release_flag("RELEASE_MOVE_VCN_TO_MAINLINE"), { + true: [ + "vcn-location-flag/module/com/android/server/vcn/VcnLocation.java", + ], + default: [ + "vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java", + ], + }), + visibility: ["//frameworks/base/services/core"], +} + java_library { name: "service-connectivity-b-pre-jarjar", sdk_version: "system_server_current", diff --git a/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java b/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java new file mode 100644 index 0000000000..6c7d24db8b --- /dev/null +++ b/Vcn/service-b/vcn-location-flag/module/com/android/server/vcn/VcnLocation.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn; + +/** + * Class to represent that VCN is in a mainline module + * + *

    This class is used to check whether VCN is in the non-updatable platform or in a mainline + * module. + */ +// When VCN is in a mainline module, this class (module/com/android/server/vcn/VcnLocation.java) +// will be built in to the vcn-location-sources filegroup. When VCN is in the non-updatable +// platform, platform/com/android/server/vcn/VcnLocation.java will be built in to the filegroup +public class VcnLocation { + /** Indicate that VCN is the platform */ + public static final boolean IS_VCN_IN_MAINLINE = true; +} diff --git a/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java b/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java new file mode 100644 index 0000000000..c6c82a55de --- /dev/null +++ b/Vcn/service-b/vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vcn; + +/** + * Class to represent that VCN is in the platform + * + *

    This class is used to check whether VCN is in the non-updatable platform or in a mainline + * module. + */ +// When VCN is in a mainline module, module/com/android/server/vcn/VcnLocation.java +// will be built in to the vcn-location-sources filegroup. When VCN is in the non-updatable +// platform, this class (platform/com/android/server/vcn/VcnLocation.java) will be built in to the +// filegroup +public class VcnLocation { + /** Indicate that VCN is the platform */ + public static final boolean IS_VCN_IN_MAINLINE = false; +} From d8d16c8154da984ff0c08fe42f1be196c80e52eb Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 21 Nov 2024 18:23:44 -0800 Subject: [PATCH 0487/1057] Move VCN utilities from services.jar to framework.jar This patch moves the VCN utilities from the systemserver classpath to boot classpath. In this way, the code consumers that do not have the source code (previously framework.jar and now services.jar) do not need to statically include the files anymore. It also removes the burden of class jarjar Bug: 288465472 Test: presubmit: FrameworksVcnTests, CtsVcnTestCases, FrameworksIkeTests, CtsIkeTestCases, VpnTest Flag: EXEMPT code refactoring; no functional change Change-Id: I7560a35727d62344c89f9a3b9ec9f0eb0058a1a2 --- .../net/vcn/VcnCellUnderlyingNetworkTemplate.java | 10 +++++----- Vcn/framework-b/src/android/net/vcn/VcnConfig.java | 6 +++--- .../android/net/vcn/VcnGatewayConnectionConfig.java | 2 +- .../net/vcn/VcnWifiUnderlyingNetworkTemplate.java | 6 +++--- .../ChildSaProposalUtils.java | 2 +- .../EapSessionConfigUtils.java | 2 +- .../IkeIdentificationUtils.java | 2 +- .../persistablebundleutils/IkeSaProposalUtils.java | 2 +- .../IkeSessionParamsUtils.java | 2 +- .../persistablebundleutils/SaProposalUtilsBase.java | 3 +-- .../TunnelModeChildSessionParamsUtils.java | 2 +- .../src/android/net/vcn/util/LogUtils.java | 2 +- .../src/android/net/vcn/util/MtuUtils.java | 2 +- .../src/android/net/vcn/util/OneWayBoolean.java | 2 +- .../net/vcn/util/PersistableBundleUtils.java | 2 +- .../com/android/server/VcnManagementService.java | 4 ++-- Vcn/service-b/src/com/android/server/vcn/Android.bp | 13 ------------- .../server/vcn/TelephonySubscriptionTracker.java | 2 +- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 2 +- .../android/server/vcn/VcnGatewayConnection.java | 8 ++++---- .../vcn/routeselection/IpSecPacketLossDetector.java | 3 ++- .../vcn/routeselection/NetworkMetricMonitor.java | 3 ++- .../routeselection/NetworkPriorityClassifier.java | 2 +- .../routeselection/UnderlyingNetworkController.java | 4 ++-- .../routeselection/UnderlyingNetworkEvaluator.java | 3 ++- .../net}/vcn/util/MtuUtilsTest.java | 4 ++-- .../net}/vcn/util/PersistableBundleUtilsTest.java | 2 +- .../android/server/VcnManagementServiceTest.java | 4 ++-- .../vcn/TelephonySubscriptionTrackerTest.java | 2 +- .../vcn/VcnGatewayConnectionConnectedStateTest.java | 2 +- .../server/vcn/VcnGatewayConnectionTest.java | 2 +- .../routeselection/IpSecPacketLossDetectorTest.java | 2 +- .../NetworkPriorityClassifierTest.java | 2 +- .../UnderlyingNetworkEvaluatorTest.java | 2 +- 34 files changed, 51 insertions(+), 62 deletions(-) delete mode 100644 Vcn/service-b/src/com/android/server/vcn/Android.bp rename Vcn/tests/unit/java/{com/android/server => android/net}/vcn/util/MtuUtilsTest.java (98%) rename Vcn/tests/unit/java/{com/android/server => android/net}/vcn/util/PersistableBundleUtilsTest.java (99%) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index c0398ce1fc..ded94159a9 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -23,18 +23,19 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.getMatchCriteriaString; +import static android.net.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; +import static android.net.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; +import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; +import static android.net.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; import static com.android.internal.annotations.VisibleForTesting.Visibility; -import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; -import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; -import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; -import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -44,7 +45,6 @@ import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java index a27e9230d4..0d0efb2f73 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnConfig.java @@ -18,10 +18,10 @@ package android.net.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; +import static android.net.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; import static com.android.internal.annotations.VisibleForTesting.Visibility; -import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; -import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; import android.annotation.IntDef; import android.annotation.NonNull; @@ -29,6 +29,7 @@ import android.annotation.Nullable; import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.vcn.util.PersistableBundleUtils; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -37,7 +38,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import com.android.server.vcn.util.PersistableBundleUtils; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java index b270062cbf..067144e6f4 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnGatewayConnectionConfig.java @@ -32,12 +32,12 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import com.android.server.vcn.util.PersistableBundleUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index c7b2f188ba..770a8c118a 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -17,22 +17,22 @@ package android.net.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; +import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; +import static android.net.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; import static com.android.internal.annotations.VisibleForTesting.Visibility; -import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; -import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.util.ArraySet; import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java index ce5ec75f01..48c1b25a97 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java @@ -20,10 +20,10 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.ipsec.ike.ChildSaProposal; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.util.List; import java.util.Objects; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java index 853a52da76..dc1ee36b71 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java @@ -28,10 +28,10 @@ import android.net.eap.EapSessionConfig.EapMsChapV2Config; import android.net.eap.EapSessionConfig.EapSimConfig; import android.net.eap.EapSessionConfig.EapTtlsConfig; import android.net.eap.EapSessionConfig.EapUiccConfig; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java index 6acb34ebb7..6e8616fc9c 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java @@ -27,10 +27,10 @@ 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 android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.net.Inet4Address; import java.net.Inet6Address; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java index 1459671f41..b590148de5 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java @@ -20,10 +20,10 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.ipsec.ike.IkeSaProposal; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.util.List; import java.util.Objects; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index d1531a119a..aefac2e89a 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -35,12 +35,12 @@ import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.net.InetAddress; import java.security.PrivateKey; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java index 0c9ee84327..469966a484 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java @@ -18,11 +18,10 @@ package android.net.vcn.persistablebundleutils; import android.annotation.NonNull; import android.net.ipsec.ike.SaProposal; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.util.Pair; -import com.android.server.vcn.util.PersistableBundleUtils; - import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java index e62acac14b..3f4ba345a1 100644 --- a/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java @@ -34,11 +34,11 @@ import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netma import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; +import android.net.vcn.util.PersistableBundleUtils; import android.os.PersistableBundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.vcn.util.PersistableBundleUtils; import java.net.Inet4Address; import java.net.Inet6Address; diff --git a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java index 93728ceb27..7f7f852716 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; import android.annotation.Nullable; import android.os.ParcelUuid; diff --git a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java index 356c71f5f2..c3123bcecf 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/MtuUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; diff --git a/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java index e79bb2d254..a7ef67b187 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java +++ b/Vcn/framework-b/src/android/net/vcn/util/OneWayBoolean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; /** * OneWayBoolean is an abstraction for a boolean that MUST only ever be flipped from false to true diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index d6761a2b37..4dc42c7827 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 2012f5632a..a45b715cca 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -55,6 +55,8 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; +import android.net.vcn.util.PersistableBundleUtils; +import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.net.wifi.WifiInfo; import android.os.Binder; import android.os.Build; @@ -90,8 +92,6 @@ import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; -import com.android.server.vcn.util.PersistableBundleUtils; -import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.io.File; import java.io.FileDescriptor; diff --git a/Vcn/service-b/src/com/android/server/vcn/Android.bp b/Vcn/service-b/src/com/android/server/vcn/Android.bp deleted file mode 100644 index ab5da3ee45..0000000000 --- a/Vcn/service-b/src/com/android/server/vcn/Android.bp +++ /dev/null @@ -1,13 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -filegroup { - name: "framework-vcn-util-sources", - srcs: ["util/**/*.java"], -} diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 3392d03910..154897eece 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; +import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; @@ -45,7 +46,6 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; -import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 1fba29779f..95acb107fd 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -38,6 +38,7 @@ import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; +import android.net.vcn.util.LogUtils; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; @@ -54,7 +55,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.util.LogUtils; import java.util.Arrays; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 2325f358e3..9ccf0401e9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -30,10 +30,10 @@ import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENAB import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.VcnManagementService.VDBG; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -78,6 +78,9 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnTransportInfo; +import android.net.vcn.util.LogUtils; +import android.net.vcn.util.MtuUtils; +import android.net.vcn.util.OneWayBoolean; import android.net.wifi.WifiInfo; import android.os.Handler; import android.os.HandlerExecutor; @@ -103,9 +106,6 @@ import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; -import com.android.server.vcn.util.LogUtils; -import com.android.server.vcn.util.MtuUtils; -import com.android.server.vcn.util.OneWayBoolean; import java.io.IOException; import java.net.Inet4Address; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 16ab51e8d6..e6a1ff9675 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -16,8 +16,9 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + import static com.android.internal.annotations.VisibleForTesting.Visibility; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.IntDef; import android.annotation.NonNull; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 0d4c373677..86cee554be 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -16,8 +16,9 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + import static com.android.server.VcnManagementService.LOCAL_LOG; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index d32e5cc8ef..79c4116d0c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -23,9 +23,9 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.VcnManagementService.LOCAL_LOG; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 3eeeece5da..f7a564ad52 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -19,12 +19,12 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; import static com.android.server.VcnManagementService.LOCAL_LOG; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -39,6 +39,7 @@ import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.net.vcn.util.LogUtils; import android.os.Handler; import android.os.HandlerExecutor; import android.os.ParcelUuid; @@ -54,7 +55,6 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; -import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 08be11e296..30f4ed1b9f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -16,8 +16,9 @@ package com.android.server.vcn.routeselection; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + import static com.android.server.VcnManagementService.LOCAL_LOG; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/util/MtuUtilsTest.java similarity index 98% rename from Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java rename to Vcn/tests/unit/java/android/net/vcn/util/MtuUtilsTest.java index e9e70783eb..47638b002f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/MtuUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/util/MtuUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; @@ -22,10 +22,10 @@ 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_HMAC_SHA2_256_128; import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; +import static android.net.vcn.util.MtuUtils.getMtu; import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU; import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; -import static com.android.server.vcn.util.MtuUtils.getMtu; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/Vcn/tests/unit/java/android/net/vcn/util/PersistableBundleUtilsTest.java similarity index 99% rename from Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java rename to Vcn/tests/unit/java/android/net/vcn/util/PersistableBundleUtilsTest.java index 9c6d85238b..c84e60086b 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java +++ b/Vcn/tests/unit/java/android/net/vcn/util/PersistableBundleUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.vcn.util; +package android.net.vcn.util; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java index 4ab8e6abbb..26a2a06367 100644 --- a/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java +++ b/Vcn/tests/unit/java/com/android/server/VcnManagementServiceTest.java @@ -77,6 +77,8 @@ import android.net.vcn.VcnConfigTest; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; +import android.net.vcn.util.PersistableBundleUtils; +import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -99,8 +101,6 @@ import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; -import com.android.server.vcn.util.PersistableBundleUtils; -import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import org.junit.Before; import org.junit.Rule; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index f1f74bca2e..b999475cba 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -19,6 +19,7 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; @@ -26,7 +27,6 @@ import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 20b7f1f146..76be232c2f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -69,6 +69,7 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnTransportInfo; +import android.net.vcn.util.MtuUtils; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; @@ -79,7 +80,6 @@ import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; -import com.android.server.vcn.util.MtuUtils; import org.junit.Before; import org.junit.Test; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 613b926167..b9fe76a24d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -25,13 +25,13 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; import static com.android.server.vcn.VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 441a4ae6d9..5db02e376f 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -19,11 +19,11 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DISABLE_DETECTOR; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM; import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index d85c5150f5..4f34f9f8f7 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -23,13 +23,13 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTR import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS; import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS; import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java index 1d6872195e..a315b0690e 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -17,9 +17,9 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY; +import static android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; From 04e8f11e25ee70a634ba4e27c3de8c924975589a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 25 Nov 2024 11:13:26 -0800 Subject: [PATCH 0488/1057] Add evitayan@ to the OWNERS file of VCN CTS Bug: 369703242 Test: build Flag: EXEMPT; OWNERS file change Change-Id: I90d29dac007e272cce5b4f0727f94d523905ea9f --- Vcn/tests/cts/OWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Vcn/tests/cts/OWNERS b/Vcn/tests/cts/OWNERS index 744d708137..48c69b9a1b 100644 --- a/Vcn/tests/cts/OWNERS +++ b/Vcn/tests/cts/OWNERS @@ -1,3 +1,4 @@ # Bug component: 826680 nharold@google.com -yangji@google.com \ No newline at end of file +evitayan@google.com +yangji@google.com #{LAST_RESORT_SUGGESTION} From df08caa4b295fbc0d1a3886ac4367a2e4325e801 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 22 Nov 2024 11:16:59 -0800 Subject: [PATCH 0489/1057] Add visibilities to VCN libs Add visibilities to framework-connectivity-b's implementation so that it can be added to framework-connectivity-test-defaults. Bug: 369703242 Test: atest CtsVcnTestCases Flag: EXEMPT no functional change Change-Id: I41422b77277edfd114fe5e9371ba69982829765d --- Vcn/framework-b/Android.bp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp index be64bb1ae4..8b010c7f2e 100644 --- a/Vcn/framework-b/Android.bp +++ b/Vcn/framework-b/Android.bp @@ -40,5 +40,28 @@ java_sdk_library { "android.net.vcn", ], + impl_library_visibility: [ + // Using for test only + "//cts/tests/netlegacy22.api", + "//cts/tests/tests/vcn", + "//external/sl4a:__subpackages__", + "//frameworks/base/core/tests/bandwidthtests", + "//frameworks/base/core/tests/benchmarks", + "//frameworks/base/core/tests/utillib", + "//frameworks/base/services/tests/VpnTests", + "//frameworks/base/tests/vcn", + "//frameworks/opt/telephony/tests/telephonytests", + "//packages/modules/CaptivePortalLogin/tests", + "//packages/modules/Connectivity/staticlibs/testutils", + "//packages/modules/Connectivity/staticlibs/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/thread/tests:__subpackages__", + "//packages/modules/IPsec/tests/iketests", + "//packages/modules/NetworkStack", + "//packages/modules/NetworkStack/tests:__subpackages__", + "//packages/modules/Wifi/service/tests/wifitests", + ], + // TODO: b/375213246 Expose this library to Tethering module } From 5abd00b03916d15495a96b25f17f98e6e9a5317b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0490/1057] Migrate VCN to separate non-updatable libraries This patch migrates VCN framework code from framework-minus-apex to framework-connectivity-b, and VCN service code to service-connectivity-b-pre-jarjar. This patch is part of the work to move VCN to the Tethering module. Design doc: go/mainline-vcn-eng-design Bug: 369703242 Test: FrameworksVcnTests, CtsVcnTestCases, CtsStrictJavaPackagesTestCases Flag: EXEMPT code refactoring; no functional change Change-Id: I747556281db2efab7115761147842d241fe283de --- Vcn/TEST_MAPPING | 8 ++ Vcn/flags/Android.bp | 38 ++++++ Vcn/framework-b/Android.bp | 72 ++++++++++- Vcn/framework-b/api/current.txt | 122 ++++++++++++++++++ Vcn/framework-b/api/module-lib-current.txt | 27 ++++ Vcn/framework-b/api/system-current.txt | 22 ++++ .../framework-vcn-jarjar-rules.txt | 2 + ...nnectivityFrameworkInitializerBaklava.java | 116 +++++++++++++++++ .../src/android/net/vcn/VcnManager.java | 8 +- .../src/android/net/vcn/util/LogUtils.java | 2 +- .../net/vcn/util/PersistableBundleUtils.java | 2 +- Vcn/service-b/Android.bp | 53 +++++++- .../android/server/VcnManagementService.java | 66 +++++----- .../src/com/android/server/vcn/TEST_MAPPING | 10 -- .../vcn/TelephonySubscriptionTracker.java | 2 +- .../src/com/android/server/vcn/Vcn.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 4 +- .../server/vcn/VcnNetworkProvider.java | 2 +- .../IpSecPacketLossDetector.java | 2 +- .../UnderlyingNetworkController.java | 2 +- Vcn/tests/unit/Android.bp | 5 +- .../vcn/TelephonySubscriptionTrackerTest.java | 3 +- 22 files changed, 513 insertions(+), 57 deletions(-) create mode 100644 Vcn/flags/Android.bp create mode 100644 Vcn/framework-b/framework-vcn-jarjar-rules.txt create mode 100644 Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java delete mode 100644 Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING diff --git a/Vcn/TEST_MAPPING b/Vcn/TEST_MAPPING index bde88fe9b7..9722a838ab 100644 --- a/Vcn/TEST_MAPPING +++ b/Vcn/TEST_MAPPING @@ -1,4 +1,12 @@ { + "presubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } + ], "postsubmit": [ { "name": "FrameworksVcnTests" diff --git a/Vcn/flags/Android.bp b/Vcn/flags/Android.bp new file mode 100644 index 0000000000..3943c6f7fe --- /dev/null +++ b/Vcn/flags/Android.bp @@ -0,0 +1,38 @@ +// +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_enigma", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +aconfig_declarations { + name: "android.net.vcn.flags-aconfig", + package: "android.net.vcn", + container: "com.android.tethering", + exportable: true, + srcs: [ + "flags.aconfig", + ], +} + +java_aconfig_library { + name: "android.net.vcn.flags-aconfig-java-export", + aconfig_declarations: "android.net.vcn.flags-aconfig", + mode: "exported", + min_sdk_version: "35", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp index 8b010c7f2e..c3121162b7 100644 --- a/Vcn/framework-b/Android.bp +++ b/Vcn/framework-b/Android.bp @@ -19,6 +19,18 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +filegroup { + name: "vcn-utils-platform-sources", + srcs: [ + "src/android/net/vcn/persistablebundleutils/**/*.java", + "src/android/net/vcn/util/**/*.java", + ], + path: "src", + visibility: [ + "//frameworks/base", // For VpnProfile.java and Vpn.java + ], +} + java_defaults { name: "framework-connectivity-b-defaults", sdk_version: "module_current", @@ -27,7 +39,25 @@ java_defaults { srcs: [ "src/**/*.java", + "src/**/*.aidl", ], + + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "app-compat-annotations", + "framework-wifi.stubs.module_lib", + "unsupportedappusage", + ], + static_libs: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", + ], + aidl: { + include_dirs: [ + // For connectivity-framework classes such as Network.aidl, NetworkCapabilities.aidl + "packages/modules/Connectivity/framework/aidl-export", + ], + }, } java_sdk_library { @@ -36,8 +66,35 @@ java_sdk_library { "framework-connectivity-b-defaults", ], + //TODO: b/375213246 Use "framework-connectivity-jarjar-rules" when VCN is + // in mainline + jarjar_rules: "framework-vcn-jarjar-rules.txt", + permitted_packages: [ + "android.net", "android.net.vcn", + "com.android.server.vcn.util", + + ], + api_packages: [ + "android.net", + "android.net.vcn", + ], + + // Allow VCN APIs to reference APIs in IKE and Connectivity + stub_only_libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "framework-connectivity.stubs.module_lib", + ], + + // To use non-jarjard names of utilities such as android.util.IndentingPrintWriter + impl_only_libs: [ + "framework-connectivity-pre-jarjar", + ], + + aconfig_declarations: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", ], impl_library_visibility: [ @@ -63,5 +120,18 @@ java_sdk_library { "//packages/modules/Wifi/service/tests/wifitests", ], - // TODO: b/375213246 Expose this library to Tethering module + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + +java_library { + name: "framework-connectivity-b-pre-jarjar", + defaults: ["framework-connectivity-b-defaults"], + libs: [ + "framework-connectivity-pre-jarjar", + ], } diff --git a/Vcn/framework-b/api/current.txt b/Vcn/framework-b/api/current.txt index d802177e24..831b74158e 100644 --- a/Vcn/framework-b/api/current.txt +++ b/Vcn/framework-b/api/current.txt @@ -1 +1,123 @@ // Signature format: 2.0 +package android.net.vcn { + + public final class VcnCellUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method public int getCbs(); + method public int getDun(); + method public int getIms(); + method public int getInternet(); + method public int getMms(); + method @NonNull public java.util.Set getOperatorPlmnIds(); + method public int getOpportunistic(); + method public int getRcs(); + method public int getRoaming(); + method @NonNull public java.util.Set getSimSpecificCarrierIds(); + } + + public static final class VcnCellUnderlyingNetworkTemplate.Builder { + ctor public VcnCellUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setCbs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setDun(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setIms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setInternet(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOperatorPlmnIds(@NonNull java.util.Set); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOpportunistic(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRcs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRoaming(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setSimSpecificCarrierIds(@NonNull java.util.Set); + } + + public final class VcnConfig implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Set getGatewayConnectionConfigs(); + method @NonNull public java.util.Set getRestrictedUnderlyingNetworkTransports(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class VcnConfig.Builder { + ctor public VcnConfig.Builder(@NonNull android.content.Context); + method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig); + method @NonNull public android.net.vcn.VcnConfig build(); + method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set); + } + + public final class VcnGatewayConnectionConfig { + method @NonNull public int[] getExposedCapabilities(); + method @NonNull public String getGatewayConnectionName(); + method @IntRange(from=0x500) public int getMaxMtu(); + method public int getMinUdpPort4500NatTimeoutSeconds(); + method @NonNull public long[] getRetryIntervalsMillis(); + method @NonNull public java.util.List getVcnUnderlyingNetworkPriorities(); + method public boolean hasGatewayOption(int); + method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff + field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 + } + + public static final class VcnGatewayConnectionConfig.Builder { + ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); + method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setSafeModeEnabled(boolean); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setVcnUnderlyingNetworkPriorities(@NonNull java.util.List); + } + + public class VcnManager { + method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; + method @NonNull public java.util.List getConfiguredSubscriptionGroups(); + method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); + method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; + method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); + field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 + field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 + field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 + field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 + field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 + field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 + field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 + } + + public abstract static class VcnManager.VcnStatusCallback { + ctor public VcnManager.VcnStatusCallback(); + method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable); + method public abstract void onStatusChanged(int); + } + + public abstract class VcnUnderlyingNetworkTemplate { + method public int getMetered(); + method public int getMinEntryDownstreamBandwidthKbps(); + method public int getMinEntryUpstreamBandwidthKbps(); + method public int getMinExitDownstreamBandwidthKbps(); + method public int getMinExitUpstreamBandwidthKbps(); + field public static final int MATCH_ANY = 0; // 0x0 + field public static final int MATCH_FORBIDDEN = 2; // 0x2 + field public static final int MATCH_REQUIRED = 1; // 0x1 + } + + public final class VcnWifiUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method @NonNull public java.util.Set getSsids(); + } + + public static final class VcnWifiUnderlyingNetworkTemplate.Builder { + ctor public VcnWifiUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setSsids(@NonNull java.util.Set); + } + +} + diff --git a/Vcn/framework-b/api/module-lib-current.txt b/Vcn/framework-b/api/module-lib-current.txt index d802177e24..8961b2830f 100644 --- a/Vcn/framework-b/api/module-lib-current.txt +++ b/Vcn/framework-b/api/module-lib-current.txt @@ -1 +1,28 @@ // Signature format: 2.0 +package android.net { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers(); + } + +} + +package android.net.vcn { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder { + ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + } + +} + diff --git a/Vcn/framework-b/api/system-current.txt b/Vcn/framework-b/api/system-current.txt index d802177e24..9c5a67701b 100644 --- a/Vcn/framework-b/api/system-current.txt +++ b/Vcn/framework-b/api/system-current.txt @@ -1 +1,23 @@ // Signature format: 2.0 +package android.net.vcn { + + public class VcnManager { + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + } + + public static interface VcnManager.VcnNetworkPolicyChangeListener { + method public void onPolicyChanged(); + } + + public final class VcnNetworkPolicyResult implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public boolean isTeardownRequested(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + +} + diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/Vcn/framework-b/framework-vcn-jarjar-rules.txt new file mode 100644 index 0000000000..757043bdbb --- /dev/null +++ b/Vcn/framework-b/framework-vcn-jarjar-rules.txt @@ -0,0 +1,2 @@ +rule android.net.vcn.persistablebundleutils.** android.net.vcn.module.repackaged.persistablebundleutils.@1 +rule android.net.vcn.util.** android.net.vcn.module.repackaged.util.@1 \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java new file mode 100644 index 0000000000..1f0fa92d79 --- /dev/null +++ b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; + +import android.annotation.FlaggedApi; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.vcn.IVcnManagementService; +import android.net.vcn.VcnManager; +import android.os.Build; +import android.os.SystemProperties; + +/** + * Class for performing registration for VCN service. + * + * @hide + */ +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerBaklava { + /** + * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers + * that depend on them. If the feature is missing, {@link Context#getSystemService} will return + * null. + * + *

    This change is specific to VcnManager. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + /** + * The corresponding vendor API for Android V + * + *

    Starting with Android V, the vendor API format has switched to YYYYMM. + * + * @see Vendor API + * level + */ + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + + private ConnectivityFrameworkInitializerBaklava() {} + + // Suppressing AndroidFrameworkCompatChange because we're querying vendor + // partition SDK level, not application's target SDK version (which BTW we + // also check through Compatibility framework a few lines below). + @Nullable + private static String getVcnFeatureDependency() { + // Check SDK version of the client app. Apps targeting pre-V SDK might + // have not checked for existence of these features. + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + return null; + } + + // Check SDK version of the vendor partition. Pre-V devices might have + // incorrectly under-declared telephony features. + final int vendorApiLevel = + SystemProperties.getInt( + "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); + if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { + return PackageManager.FEATURE_TELEPHONY; + } else { + return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + } + } + + /** + * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return + * a VcnManager. + * + * @throws IllegalStateException if this is called anywhere besides {@link + * SystemServiceRegistry}. + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + VcnManager.VCN_MANAGEMENT_SERVICE_STRING, + VcnManager.class, + (context, serviceBinder) -> { + final String telephonyFeatureToCheck = getVcnFeatureDependency(); + if (telephonyFeatureToCheck != null + && !context.getPackageManager() + .hasSystemFeature(telephonyFeatureToCheck)) { + return null; + } + IVcnManagementService service = + IVcnManagementService.Stub.asInterface(serviceBinder); + return new VcnManager(context, service); + }); + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index f275714e2c..594bbb8a20 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -334,7 +334,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnUnderlyingNetworkPolicyListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already * registered * @hide @@ -423,7 +423,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnNetworkPolicyChangeListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already * registered * @hide @@ -455,7 +455,7 @@ public class VcnManager { *

    If the specified listener is not currently registered, this is a no-op. * * @param listener the VcnNetworkPolicyChangeListener that will be removed - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @hide */ @SystemApi @@ -489,7 +489,7 @@ public class VcnManager { * policy result for this Network. * @param linkProperties the LinkProperties to be used in determining the Network policy result * for this Network. - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @return the {@link VcnNetworkPolicyResult} to be used for this Network. * @hide */ diff --git a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java index 7f7f852716..742aa761e6 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java @@ -19,7 +19,7 @@ package android.net.vcn.util; import android.annotation.Nullable; import android.os.ParcelUuid; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; /** @hide */ public class LogUtils { diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 4dc42c7827..8a687d8c59 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.os.ParcelUuid; import android.os.PersistableBundle; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 03ef4e67af..26d8397494 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -32,6 +32,33 @@ filegroup { visibility: ["//frameworks/base/services/core"], } +// Do not static include this lib in VCN because these files exist in +// both service-connectivity.jar and framework.jar +// TODO: b/374174952 After VCN moves to Connectivity/ and the modularization is done +// this lib can be removed and "service-connectivity-b-pre-jarjar" can include +// "service-connectivity-pre-jarjar" +java_library { + name: "connectivity-utils-service-vcn-internal", + sdk_version: "module_current", + min_sdk_version: "30", + srcs: [ + ":framework-connectivity-shared-srcs", + ], + libs: [ + "framework-annotations-lib", + "unsupportedappusage", + ], + visibility: [ + "//visibility:private", + ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + java_library { name: "service-connectivity-b-pre-jarjar", sdk_version: "system_server_current", @@ -42,8 +69,32 @@ java_library { "src/**/*.java", ], - // TODO: b/375213246 Expose this library to Tethering module + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "connectivity-utils-service-vcn-internal", + "framework-annotations-lib", + "framework-connectivity-pre-jarjar", + "framework-connectivity-t-pre-jarjar", + "framework-connectivity-b-pre-jarjar", + "framework-wifi.stubs.module_lib", + "modules-utils-statemachine", + "unsupportedappusage", + ], + + // TODO: b/374174952 Dynamically include these libs when VCN + // modularization is released + static_libs: [ + "net-utils-service-vcn", + "modules-utils-handlerexecutor", + ], + visibility: [ "//frameworks/base/services", ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index a45b715cca..26db6a988e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -86,6 +86,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.HandlerUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -1332,41 +1333,46 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| "); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. - mHandler.runWithScissors(() -> { - mNetworkProvider.dump(pw); - pw.println(); + HandlerUtils.runWithScissorsForDump( + mHandler, + () -> { + mNetworkProvider.dump(pw); + pw.println(); - mTrackingNetworkCallback.dump(pw); - pw.println(); + mTrackingNetworkCallback.dump(pw); + pw.println(); - synchronized (mLock) { - mLastSnapshot.dump(pw); - pw.println(); + synchronized (mLock) { + mLastSnapshot.dump(pw); + pw.println(); - pw.println("mConfigs:"); - pw.increaseIndent(); - for (Entry entry : mConfigs.entrySet()) { - pw.println(entry.getKey() + ": " - + entry.getValue().getProvisioningPackageName()); - } - pw.decreaseIndent(); - pw.println(); + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println( + entry.getKey() + + ": " + + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); - pw.println("mVcns:"); - pw.increaseIndent(); - for (Vcn vcn : mVcns.values()) { - vcn.dump(pw); - } - pw.decreaseIndent(); - pw.println(); - } + pw.println("mVcns:"); + pw.increaseIndent(); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.decreaseIndent(); + pw.println(); + } - pw.println("Local log:"); - pw.increaseIndent(); - LOCAL_LOG.dump(pw); - pw.decreaseIndent(); - pw.println(); - }, DUMP_TIMEOUT_MILLIS); + pw.println("Local log:"); + pw.increaseIndent(); + LOCAL_LOG.dump(pw); + pw.decreaseIndent(); + pw.println(); + }, + DUMP_TIMEOUT_MILLIS); } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService diff --git a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING b/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING deleted file mode 100644 index 5b04d884fc..0000000000 --- a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "FrameworksVcnTests" - }, - { - "name": "CtsVcnTestCases" - } - ] -} \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 154897eece..b448f7595b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -29,7 +29,6 @@ import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -46,6 +45,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 95acb107fd..2524d0eeda 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -40,7 +40,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; @@ -53,6 +52,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 9ccf0401e9..f024b5f05b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -45,6 +45,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.IpSecManager.IpSecTunnelInterface; +import android.net.IpSecManager.PolicyDirection; import android.net.IpSecManager.ResourceUnavailableException; import android.net.IpSecTransform; import android.net.LinkAddress; @@ -59,7 +60,6 @@ import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; -import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; @@ -83,7 +83,6 @@ import android.net.vcn.util.MtuUtils; import android.net.vcn.util.OneWayBoolean; import android.net.wifi.WifiInfo; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; @@ -101,6 +100,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 78ff432f54..4552f509b5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -33,7 +33,6 @@ import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.vcn.VcnGatewayConnectionConfig; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; import android.util.IndentingPrintWriter; @@ -41,6 +40,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.Objects; import java.util.Set; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index e6a1ff9675..72de61363d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -32,12 +32,12 @@ import android.net.IpSecTransformState; import android.net.Network; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.OutcomeReceiver; import android.os.PowerManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.VcnContext; import java.lang.annotation.ElementType; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index f7a564ad52..29a0762f5f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -41,7 +41,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; @@ -52,6 +51,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index b16ba15a68..51a300bff7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -14,21 +14,24 @@ package { android_test { name: "FrameworksVcnTests", + // For access hidden connectivity methods in tests + defaults: ["framework-connectivity-test-defaults"], srcs: [ "java/**/*.java", "java/**/*.kt", ], platform_apis: true, - defaults: ["framework-connectivity-test-defaults"], test_suites: ["device-tests"], certificate: "platform", static_libs: [ + "android.net.vcn.flags-aconfig-java-export", "androidx.test.rules", "frameworks-base-testutils", "framework-protos", "mockito-target-minus-junit4", "net-tests-utils", "platform-test-annotations", + "service-connectivity-b-pre-jarjar", "services.core", "service-connectivity-tiramisu-pre-jarjar", "flag-junit", diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index b999475cba..77f82f0d8c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -55,7 +55,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; @@ -72,6 +71,8 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.HandlerExecutor; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; From e070c4ee3cfb0c29092204ab65d3bb554d7da404 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 24 Oct 2024 17:55:58 +0000 Subject: [PATCH 0491/1057] Allow SystemServer to create VCN service with a service initializer We need to use "startService" to load the service via reflection because the followup CLs will use a build system flag to control whether the service is in Tethering module or the platform. Using reflection ensures that in both case the system can build Bug: 366598445 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT no functional change Change-Id: I165e83135c557619518257eb79a00b9ce5802c76 --- Vcn/service-b/Android.bp | 1 + .../ConnectivityServiceInitializerB.java | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 26d8397494..c1a1ee7875 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -77,6 +77,7 @@ java_library { "framework-connectivity-t-pre-jarjar", "framework-connectivity-b-pre-jarjar", "framework-wifi.stubs.module_lib", + "keepanno-annotations", "modules-utils-statemachine", "unsupportedappusage", ], diff --git a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java new file mode 100644 index 0000000000..02c8ce4f29 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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; + +import android.content.Context; +import android.util.Log; + +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.UsedByReflection; + +/** + * Service initializer for VCN. This is called by system server to create a new instance of + * VcnManagementService. + */ +// This class is reflectively invoked from SystemServer and ConnectivityServiceInitializer. +// Without this annotation, this class will be treated as unused class and be removed during build +// time. +@UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS) +public final class ConnectivityServiceInitializerB extends SystemService { + private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName(); + private final VcnManagementService mVcnManagementService; + + public ConnectivityServiceInitializerB(Context context) { + super(context); + mVcnManagementService = VcnManagementService.create(context); + } + + @Override + public void onStart() { + if (mVcnManagementService != null) { + Log.i(TAG, "Registering " + Context.VCN_MANAGEMENT_SERVICE); + publishBinderService( + Context.VCN_MANAGEMENT_SERVICE, + mVcnManagementService, + /* allowIsolated= */ false); + } + } + + @Override + public void onBootPhase(int phase) { + if (mVcnManagementService != null && phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + Log.i(TAG, "Starting " + Context.VCN_MANAGEMENT_SERVICE); + mVcnManagementService.systemReady(); + } + } +} From 94a895c618d6491e6f6ecdc650df9b0af1d17773 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 27 Nov 2024 16:40:15 -0800 Subject: [PATCH 0492/1057] Clean up safe_mode_config flag check in the functional code This patch cleans up the flag check in the functional code. The flag is already fully released in Android V At the same time, the flag definition is not removed because it is an exportable flag Bug: 380326369 Bug: 276358140 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT, clean up released flag Change-Id: I985d37e192c4bc87ebd433f4de3b7fe93b039f7d --- .../server/vcn/VcnGatewayConnection.java | 5 +--- ...cnGatewayConnectionConnectedStateTest.java | 24 ++----------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 9ccf0401e9..77bda9dc6b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1228,10 +1228,7 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { - final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig(); - logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled); - - if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) { + if (!mConnectionConfig.isSafeModeEnabled()) { logVdbg("setSafeModeAlarm: safe mode disabled"); return; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 76be232c2f..74db6a5211 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -659,7 +659,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection private void verifySetSafeModeAlarm( boolean safeModeEnabledByCaller, - boolean safeModeConfigFlagEnabled, boolean expectingSafeModeEnabled) throws Exception { final VcnGatewayConnectionConfig config = @@ -670,7 +669,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mock(VcnGatewayConnection.Dependencies.class); setUpWakeupMessage( mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps); - doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig(); final VcnGatewayConnection connection = new VcnGatewayConnection( @@ -694,37 +692,19 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } @Test - public void testSafeModeEnabled_configFlagEnabled() throws Exception { + public void testSafeModeEnabled() throws Exception { verifySetSafeModeAlarm( true /* safeModeEnabledByCaller */, - true /* safeModeConfigFlagEnabled */, true /* expectingSafeModeEnabled */); } @Test - public void testSafeModeEnabled_configFlagDisabled() throws Exception { - verifySetSafeModeAlarm( - true /* safeModeEnabledByCaller */, - false /* safeModeConfigFlagEnabled */, - true /* expectingSafeModeEnabled */); - } - - @Test - public void testSafeModeDisabled_configFlagEnabled() throws Exception { + public void testSafeModeDisabled() throws Exception { verifySetSafeModeAlarm( false /* safeModeEnabledByCaller */, - true /* safeModeConfigFlagEnabled */, false /* expectingSafeModeEnabled */); } - @Test - public void testSafeModeDisabled_configFlagDisabled() throws Exception { - verifySetSafeModeAlarm( - false /* safeModeEnabledByCaller */, - false /* safeModeConfigFlagEnabled */, - true /* expectingSafeModeEnabled */); - } - private Consumer setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); From 88aa480e8db78be78042fa920c23990c5938ff0e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 27 Nov 2024 16:40:15 -0800 Subject: [PATCH 0493/1057] Clean up safe_mode_config flag check in the functional code This patch cleans up the flag check in the functional code. The flag is already fully released in Android V At the same time, the flag definition is not removed because it is an exportable flag Bug: 380326369 Bug: 276358140 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT, clean up released flag Change-Id: I985d37e192c4bc87ebd433f4de3b7fe93b039f7d --- .../server/vcn/VcnGatewayConnection.java | 5 +--- ...cnGatewayConnectionConnectedStateTest.java | 24 ++----------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index f024b5f05b..e50fc3a6e8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -1228,10 +1228,7 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { - final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig(); - logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled); - - if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) { + if (!mConnectionConfig.isSafeModeEnabled()) { logVdbg("setSafeModeAlarm: safe mode disabled"); return; } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 76be232c2f..74db6a5211 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -659,7 +659,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection private void verifySetSafeModeAlarm( boolean safeModeEnabledByCaller, - boolean safeModeConfigFlagEnabled, boolean expectingSafeModeEnabled) throws Exception { final VcnGatewayConnectionConfig config = @@ -670,7 +669,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mock(VcnGatewayConnection.Dependencies.class); setUpWakeupMessage( mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps); - doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig(); final VcnGatewayConnection connection = new VcnGatewayConnection( @@ -694,37 +692,19 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection } @Test - public void testSafeModeEnabled_configFlagEnabled() throws Exception { + public void testSafeModeEnabled() throws Exception { verifySetSafeModeAlarm( true /* safeModeEnabledByCaller */, - true /* safeModeConfigFlagEnabled */, true /* expectingSafeModeEnabled */); } @Test - public void testSafeModeEnabled_configFlagDisabled() throws Exception { - verifySetSafeModeAlarm( - true /* safeModeEnabledByCaller */, - false /* safeModeConfigFlagEnabled */, - true /* expectingSafeModeEnabled */); - } - - @Test - public void testSafeModeDisabled_configFlagEnabled() throws Exception { + public void testSafeModeDisabled() throws Exception { verifySetSafeModeAlarm( false /* safeModeEnabledByCaller */, - true /* safeModeConfigFlagEnabled */, false /* expectingSafeModeEnabled */); } - @Test - public void testSafeModeDisabled_configFlagDisabled() throws Exception { - verifySetSafeModeAlarm( - false /* safeModeEnabledByCaller */, - false /* safeModeConfigFlagEnabled */, - true /* expectingSafeModeEnabled */); - } - private Consumer setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); From d5194f1527b61270f7c07ce7e585e83ce26841f8 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0494/1057] Migrate VCN to separate non-updatable libraries This patch migrates VCN framework code from framework-minus-apex to framework-connectivity-b, and VCN service code to service-connectivity-b-pre-jarjar. This patch is part of the work to move VCN to the Tethering module. Design doc: go/mainline-vcn-eng-design Bug: 369703242 Test: FrameworksVcnTests, CtsVcnTestCases, CtsStrictJavaPackagesTestCases Flag: EXEMPT code refactoring; no functional change (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5abd00b03916d15495a96b25f17f98e6e9a5317b) Change-Id: I747556281db2efab7115761147842d241fe283de Merged-In: I747556281db2efab7115761147842d241fe283de --- Vcn/TEST_MAPPING | 8 ++ Vcn/flags/Android.bp | 38 ++++++ Vcn/framework-b/Android.bp | 72 ++++++++++- Vcn/framework-b/api/current.txt | 122 ++++++++++++++++++ Vcn/framework-b/api/module-lib-current.txt | 27 ++++ Vcn/framework-b/api/system-current.txt | 22 ++++ .../framework-vcn-jarjar-rules.txt | 2 + ...nnectivityFrameworkInitializerBaklava.java | 116 +++++++++++++++++ .../src/android/net/vcn/VcnManager.java | 8 +- .../src/android/net/vcn/util/LogUtils.java | 2 +- .../net/vcn/util/PersistableBundleUtils.java | 2 +- Vcn/service-b/Android.bp | 53 +++++++- .../android/server/VcnManagementService.java | 66 +++++----- .../src/com/android/server/vcn/TEST_MAPPING | 10 -- .../vcn/TelephonySubscriptionTracker.java | 2 +- .../src/com/android/server/vcn/Vcn.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 4 +- .../server/vcn/VcnNetworkProvider.java | 2 +- .../IpSecPacketLossDetector.java | 2 +- .../UnderlyingNetworkController.java | 2 +- Vcn/tests/unit/Android.bp | 5 +- .../vcn/TelephonySubscriptionTrackerTest.java | 3 +- 22 files changed, 513 insertions(+), 57 deletions(-) create mode 100644 Vcn/flags/Android.bp create mode 100644 Vcn/framework-b/framework-vcn-jarjar-rules.txt create mode 100644 Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java delete mode 100644 Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING diff --git a/Vcn/TEST_MAPPING b/Vcn/TEST_MAPPING index bde88fe9b7..9722a838ab 100644 --- a/Vcn/TEST_MAPPING +++ b/Vcn/TEST_MAPPING @@ -1,4 +1,12 @@ { + "presubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } + ], "postsubmit": [ { "name": "FrameworksVcnTests" diff --git a/Vcn/flags/Android.bp b/Vcn/flags/Android.bp new file mode 100644 index 0000000000..3943c6f7fe --- /dev/null +++ b/Vcn/flags/Android.bp @@ -0,0 +1,38 @@ +// +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_enigma", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +aconfig_declarations { + name: "android.net.vcn.flags-aconfig", + package: "android.net.vcn", + container: "com.android.tethering", + exportable: true, + srcs: [ + "flags.aconfig", + ], +} + +java_aconfig_library { + name: "android.net.vcn.flags-aconfig-java-export", + aconfig_declarations: "android.net.vcn.flags-aconfig", + mode: "exported", + min_sdk_version: "35", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp index 8b010c7f2e..c3121162b7 100644 --- a/Vcn/framework-b/Android.bp +++ b/Vcn/framework-b/Android.bp @@ -19,6 +19,18 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +filegroup { + name: "vcn-utils-platform-sources", + srcs: [ + "src/android/net/vcn/persistablebundleutils/**/*.java", + "src/android/net/vcn/util/**/*.java", + ], + path: "src", + visibility: [ + "//frameworks/base", // For VpnProfile.java and Vpn.java + ], +} + java_defaults { name: "framework-connectivity-b-defaults", sdk_version: "module_current", @@ -27,7 +39,25 @@ java_defaults { srcs: [ "src/**/*.java", + "src/**/*.aidl", ], + + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "app-compat-annotations", + "framework-wifi.stubs.module_lib", + "unsupportedappusage", + ], + static_libs: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", + ], + aidl: { + include_dirs: [ + // For connectivity-framework classes such as Network.aidl, NetworkCapabilities.aidl + "packages/modules/Connectivity/framework/aidl-export", + ], + }, } java_sdk_library { @@ -36,8 +66,35 @@ java_sdk_library { "framework-connectivity-b-defaults", ], + //TODO: b/375213246 Use "framework-connectivity-jarjar-rules" when VCN is + // in mainline + jarjar_rules: "framework-vcn-jarjar-rules.txt", + permitted_packages: [ + "android.net", "android.net.vcn", + "com.android.server.vcn.util", + + ], + api_packages: [ + "android.net", + "android.net.vcn", + ], + + // Allow VCN APIs to reference APIs in IKE and Connectivity + stub_only_libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "framework-connectivity.stubs.module_lib", + ], + + // To use non-jarjard names of utilities such as android.util.IndentingPrintWriter + impl_only_libs: [ + "framework-connectivity-pre-jarjar", + ], + + aconfig_declarations: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", ], impl_library_visibility: [ @@ -63,5 +120,18 @@ java_sdk_library { "//packages/modules/Wifi/service/tests/wifitests", ], - // TODO: b/375213246 Expose this library to Tethering module + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + +java_library { + name: "framework-connectivity-b-pre-jarjar", + defaults: ["framework-connectivity-b-defaults"], + libs: [ + "framework-connectivity-pre-jarjar", + ], } diff --git a/Vcn/framework-b/api/current.txt b/Vcn/framework-b/api/current.txt index d802177e24..831b74158e 100644 --- a/Vcn/framework-b/api/current.txt +++ b/Vcn/framework-b/api/current.txt @@ -1 +1,123 @@ // Signature format: 2.0 +package android.net.vcn { + + public final class VcnCellUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method public int getCbs(); + method public int getDun(); + method public int getIms(); + method public int getInternet(); + method public int getMms(); + method @NonNull public java.util.Set getOperatorPlmnIds(); + method public int getOpportunistic(); + method public int getRcs(); + method public int getRoaming(); + method @NonNull public java.util.Set getSimSpecificCarrierIds(); + } + + public static final class VcnCellUnderlyingNetworkTemplate.Builder { + ctor public VcnCellUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setCbs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setDun(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setIms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setInternet(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOperatorPlmnIds(@NonNull java.util.Set); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOpportunistic(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRcs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRoaming(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setSimSpecificCarrierIds(@NonNull java.util.Set); + } + + public final class VcnConfig implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Set getGatewayConnectionConfigs(); + method @NonNull public java.util.Set getRestrictedUnderlyingNetworkTransports(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class VcnConfig.Builder { + ctor public VcnConfig.Builder(@NonNull android.content.Context); + method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig); + method @NonNull public android.net.vcn.VcnConfig build(); + method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set); + } + + public final class VcnGatewayConnectionConfig { + method @NonNull public int[] getExposedCapabilities(); + method @NonNull public String getGatewayConnectionName(); + method @IntRange(from=0x500) public int getMaxMtu(); + method public int getMinUdpPort4500NatTimeoutSeconds(); + method @NonNull public long[] getRetryIntervalsMillis(); + method @NonNull public java.util.List getVcnUnderlyingNetworkPriorities(); + method public boolean hasGatewayOption(int); + method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff + field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 + } + + public static final class VcnGatewayConnectionConfig.Builder { + ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); + method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setSafeModeEnabled(boolean); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setVcnUnderlyingNetworkPriorities(@NonNull java.util.List); + } + + public class VcnManager { + method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; + method @NonNull public java.util.List getConfiguredSubscriptionGroups(); + method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); + method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; + method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); + field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 + field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 + field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 + field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 + field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 + field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 + field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 + } + + public abstract static class VcnManager.VcnStatusCallback { + ctor public VcnManager.VcnStatusCallback(); + method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable); + method public abstract void onStatusChanged(int); + } + + public abstract class VcnUnderlyingNetworkTemplate { + method public int getMetered(); + method public int getMinEntryDownstreamBandwidthKbps(); + method public int getMinEntryUpstreamBandwidthKbps(); + method public int getMinExitDownstreamBandwidthKbps(); + method public int getMinExitUpstreamBandwidthKbps(); + field public static final int MATCH_ANY = 0; // 0x0 + field public static final int MATCH_FORBIDDEN = 2; // 0x2 + field public static final int MATCH_REQUIRED = 1; // 0x1 + } + + public final class VcnWifiUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method @NonNull public java.util.Set getSsids(); + } + + public static final class VcnWifiUnderlyingNetworkTemplate.Builder { + ctor public VcnWifiUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setSsids(@NonNull java.util.Set); + } + +} + diff --git a/Vcn/framework-b/api/module-lib-current.txt b/Vcn/framework-b/api/module-lib-current.txt index d802177e24..8961b2830f 100644 --- a/Vcn/framework-b/api/module-lib-current.txt +++ b/Vcn/framework-b/api/module-lib-current.txt @@ -1 +1,28 @@ // Signature format: 2.0 +package android.net { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers(); + } + +} + +package android.net.vcn { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder { + ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + } + +} + diff --git a/Vcn/framework-b/api/system-current.txt b/Vcn/framework-b/api/system-current.txt index d802177e24..9c5a67701b 100644 --- a/Vcn/framework-b/api/system-current.txt +++ b/Vcn/framework-b/api/system-current.txt @@ -1 +1,23 @@ // Signature format: 2.0 +package android.net.vcn { + + public class VcnManager { + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + } + + public static interface VcnManager.VcnNetworkPolicyChangeListener { + method public void onPolicyChanged(); + } + + public final class VcnNetworkPolicyResult implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public boolean isTeardownRequested(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + +} + diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/Vcn/framework-b/framework-vcn-jarjar-rules.txt new file mode 100644 index 0000000000..757043bdbb --- /dev/null +++ b/Vcn/framework-b/framework-vcn-jarjar-rules.txt @@ -0,0 +1,2 @@ +rule android.net.vcn.persistablebundleutils.** android.net.vcn.module.repackaged.persistablebundleutils.@1 +rule android.net.vcn.util.** android.net.vcn.module.repackaged.util.@1 \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java new file mode 100644 index 0000000000..1f0fa92d79 --- /dev/null +++ b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; + +import android.annotation.FlaggedApi; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.vcn.IVcnManagementService; +import android.net.vcn.VcnManager; +import android.os.Build; +import android.os.SystemProperties; + +/** + * Class for performing registration for VCN service. + * + * @hide + */ +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerBaklava { + /** + * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers + * that depend on them. If the feature is missing, {@link Context#getSystemService} will return + * null. + * + *

    This change is specific to VcnManager. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + /** + * The corresponding vendor API for Android V + * + *

    Starting with Android V, the vendor API format has switched to YYYYMM. + * + * @see Vendor API + * level + */ + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + + private ConnectivityFrameworkInitializerBaklava() {} + + // Suppressing AndroidFrameworkCompatChange because we're querying vendor + // partition SDK level, not application's target SDK version (which BTW we + // also check through Compatibility framework a few lines below). + @Nullable + private static String getVcnFeatureDependency() { + // Check SDK version of the client app. Apps targeting pre-V SDK might + // have not checked for existence of these features. + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + return null; + } + + // Check SDK version of the vendor partition. Pre-V devices might have + // incorrectly under-declared telephony features. + final int vendorApiLevel = + SystemProperties.getInt( + "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); + if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { + return PackageManager.FEATURE_TELEPHONY; + } else { + return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + } + } + + /** + * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return + * a VcnManager. + * + * @throws IllegalStateException if this is called anywhere besides {@link + * SystemServiceRegistry}. + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + VcnManager.VCN_MANAGEMENT_SERVICE_STRING, + VcnManager.class, + (context, serviceBinder) -> { + final String telephonyFeatureToCheck = getVcnFeatureDependency(); + if (telephonyFeatureToCheck != null + && !context.getPackageManager() + .hasSystemFeature(telephonyFeatureToCheck)) { + return null; + } + IVcnManagementService service = + IVcnManagementService.Stub.asInterface(serviceBinder); + return new VcnManager(context, service); + }); + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index f275714e2c..594bbb8a20 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -334,7 +334,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnUnderlyingNetworkPolicyListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already * registered * @hide @@ -423,7 +423,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnNetworkPolicyChangeListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already * registered * @hide @@ -455,7 +455,7 @@ public class VcnManager { *

    If the specified listener is not currently registered, this is a no-op. * * @param listener the VcnNetworkPolicyChangeListener that will be removed - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @hide */ @SystemApi @@ -489,7 +489,7 @@ public class VcnManager { * policy result for this Network. * @param linkProperties the LinkProperties to be used in determining the Network policy result * for this Network. - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @return the {@link VcnNetworkPolicyResult} to be used for this Network. * @hide */ diff --git a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java index 7f7f852716..742aa761e6 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java @@ -19,7 +19,7 @@ package android.net.vcn.util; import android.annotation.Nullable; import android.os.ParcelUuid; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; /** @hide */ public class LogUtils { diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 4dc42c7827..8a687d8c59 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.os.ParcelUuid; import android.os.PersistableBundle; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 03ef4e67af..26d8397494 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -32,6 +32,33 @@ filegroup { visibility: ["//frameworks/base/services/core"], } +// Do not static include this lib in VCN because these files exist in +// both service-connectivity.jar and framework.jar +// TODO: b/374174952 After VCN moves to Connectivity/ and the modularization is done +// this lib can be removed and "service-connectivity-b-pre-jarjar" can include +// "service-connectivity-pre-jarjar" +java_library { + name: "connectivity-utils-service-vcn-internal", + sdk_version: "module_current", + min_sdk_version: "30", + srcs: [ + ":framework-connectivity-shared-srcs", + ], + libs: [ + "framework-annotations-lib", + "unsupportedappusage", + ], + visibility: [ + "//visibility:private", + ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + java_library { name: "service-connectivity-b-pre-jarjar", sdk_version: "system_server_current", @@ -42,8 +69,32 @@ java_library { "src/**/*.java", ], - // TODO: b/375213246 Expose this library to Tethering module + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "connectivity-utils-service-vcn-internal", + "framework-annotations-lib", + "framework-connectivity-pre-jarjar", + "framework-connectivity-t-pre-jarjar", + "framework-connectivity-b-pre-jarjar", + "framework-wifi.stubs.module_lib", + "modules-utils-statemachine", + "unsupportedappusage", + ], + + // TODO: b/374174952 Dynamically include these libs when VCN + // modularization is released + static_libs: [ + "net-utils-service-vcn", + "modules-utils-handlerexecutor", + ], + visibility: [ "//frameworks/base/services", ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index a45b715cca..26db6a988e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -86,6 +86,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.HandlerUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -1332,41 +1333,46 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| "); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. - mHandler.runWithScissors(() -> { - mNetworkProvider.dump(pw); - pw.println(); + HandlerUtils.runWithScissorsForDump( + mHandler, + () -> { + mNetworkProvider.dump(pw); + pw.println(); - mTrackingNetworkCallback.dump(pw); - pw.println(); + mTrackingNetworkCallback.dump(pw); + pw.println(); - synchronized (mLock) { - mLastSnapshot.dump(pw); - pw.println(); + synchronized (mLock) { + mLastSnapshot.dump(pw); + pw.println(); - pw.println("mConfigs:"); - pw.increaseIndent(); - for (Entry entry : mConfigs.entrySet()) { - pw.println(entry.getKey() + ": " - + entry.getValue().getProvisioningPackageName()); - } - pw.decreaseIndent(); - pw.println(); + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println( + entry.getKey() + + ": " + + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); - pw.println("mVcns:"); - pw.increaseIndent(); - for (Vcn vcn : mVcns.values()) { - vcn.dump(pw); - } - pw.decreaseIndent(); - pw.println(); - } + pw.println("mVcns:"); + pw.increaseIndent(); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.decreaseIndent(); + pw.println(); + } - pw.println("Local log:"); - pw.increaseIndent(); - LOCAL_LOG.dump(pw); - pw.decreaseIndent(); - pw.println(); - }, DUMP_TIMEOUT_MILLIS); + pw.println("Local log:"); + pw.increaseIndent(); + LOCAL_LOG.dump(pw); + pw.decreaseIndent(); + pw.println(); + }, + DUMP_TIMEOUT_MILLIS); } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService diff --git a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING b/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING deleted file mode 100644 index 5b04d884fc..0000000000 --- a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "FrameworksVcnTests" - }, - { - "name": "CtsVcnTestCases" - } - ] -} \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 154897eece..b448f7595b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -29,7 +29,6 @@ import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -46,6 +45,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 95acb107fd..2524d0eeda 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -40,7 +40,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; @@ -53,6 +52,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 77bda9dc6b..e50fc3a6e8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -45,6 +45,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.IpSecManager.IpSecTunnelInterface; +import android.net.IpSecManager.PolicyDirection; import android.net.IpSecManager.ResourceUnavailableException; import android.net.IpSecTransform; import android.net.LinkAddress; @@ -59,7 +60,6 @@ import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; -import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; @@ -83,7 +83,6 @@ import android.net.vcn.util.MtuUtils; import android.net.vcn.util.OneWayBoolean; import android.net.wifi.WifiInfo; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; @@ -101,6 +100,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 78ff432f54..4552f509b5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -33,7 +33,6 @@ import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.vcn.VcnGatewayConnectionConfig; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; import android.util.IndentingPrintWriter; @@ -41,6 +40,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.Objects; import java.util.Set; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index e6a1ff9675..72de61363d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -32,12 +32,12 @@ import android.net.IpSecTransformState; import android.net.Network; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.OutcomeReceiver; import android.os.PowerManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.VcnContext; import java.lang.annotation.ElementType; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index f7a564ad52..29a0762f5f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -41,7 +41,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; @@ -52,6 +51,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index b16ba15a68..51a300bff7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -14,21 +14,24 @@ package { android_test { name: "FrameworksVcnTests", + // For access hidden connectivity methods in tests + defaults: ["framework-connectivity-test-defaults"], srcs: [ "java/**/*.java", "java/**/*.kt", ], platform_apis: true, - defaults: ["framework-connectivity-test-defaults"], test_suites: ["device-tests"], certificate: "platform", static_libs: [ + "android.net.vcn.flags-aconfig-java-export", "androidx.test.rules", "frameworks-base-testutils", "framework-protos", "mockito-target-minus-junit4", "net-tests-utils", "platform-test-annotations", + "service-connectivity-b-pre-jarjar", "services.core", "service-connectivity-tiramisu-pre-jarjar", "flag-junit", diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index b999475cba..77f82f0d8c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -55,7 +55,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; @@ -72,6 +71,8 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.HandlerExecutor; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; From 68e2a7be967c7138ea7b3adc257103558c9ad8a9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 24 Oct 2024 17:55:58 +0000 Subject: [PATCH 0495/1057] Allow SystemServer to create VCN service with a service initializer We need to use "startService" to load the service via reflection because the followup CLs will use a build system flag to control whether the service is in Tethering module or the platform. Using reflection ensures that in both case the system can build Bug: 366598445 Test: atest FrameworksVcnTests && atest CtsVcnTestCases Flag: EXEMPT no functional change (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e070c4ee3cfb0c29092204ab65d3bb554d7da404) Change-Id: I165e83135c557619518257eb79a00b9ce5802c76 Merged-In: I165e83135c557619518257eb79a00b9ce5802c76 --- Vcn/service-b/Android.bp | 1 + .../ConnectivityServiceInitializerB.java | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 26d8397494..c1a1ee7875 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -77,6 +77,7 @@ java_library { "framework-connectivity-t-pre-jarjar", "framework-connectivity-b-pre-jarjar", "framework-wifi.stubs.module_lib", + "keepanno-annotations", "modules-utils-statemachine", "unsupportedappusage", ], diff --git a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java new file mode 100644 index 0000000000..02c8ce4f29 --- /dev/null +++ b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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; + +import android.content.Context; +import android.util.Log; + +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.UsedByReflection; + +/** + * Service initializer for VCN. This is called by system server to create a new instance of + * VcnManagementService. + */ +// This class is reflectively invoked from SystemServer and ConnectivityServiceInitializer. +// Without this annotation, this class will be treated as unused class and be removed during build +// time. +@UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS) +public final class ConnectivityServiceInitializerB extends SystemService { + private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName(); + private final VcnManagementService mVcnManagementService; + + public ConnectivityServiceInitializerB(Context context) { + super(context); + mVcnManagementService = VcnManagementService.create(context); + } + + @Override + public void onStart() { + if (mVcnManagementService != null) { + Log.i(TAG, "Registering " + Context.VCN_MANAGEMENT_SERVICE); + publishBinderService( + Context.VCN_MANAGEMENT_SERVICE, + mVcnManagementService, + /* allowIsolated= */ false); + } + } + + @Override + public void onBootPhase(int phase) { + if (mVcnManagementService != null && phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + Log.i(TAG, "Starting " + Context.VCN_MANAGEMENT_SERVICE); + mVcnManagementService.systemReady(); + } + } +} From 675b2ee28aa63584f89a1ba79d9d2e56b9228097 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 1 Oct 2024 02:11:28 +0000 Subject: [PATCH 0496/1057] Migrate VCN to separate non-updatable libraries This patch migrates VCN framework code from framework-minus-apex to framework-connectivity-b, and VCN service code to service-connectivity-b-pre-jarjar. This patch is part of the work to move VCN to the Tethering module. Design doc: go/mainline-vcn-eng-design Bug: 369703242 Test: FrameworksVcnTests, CtsVcnTestCases, CtsStrictJavaPackagesTestCases Flag: EXEMPT code refactoring; no functional change (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5abd00b03916d15495a96b25f17f98e6e9a5317b) Merged-In: I747556281db2efab7115761147842d241fe283de Change-Id: I747556281db2efab7115761147842d241fe283de --- Vcn/TEST_MAPPING | 8 ++ Vcn/flags/Android.bp | 38 ++++++ Vcn/framework-b/Android.bp | 72 ++++++++++- Vcn/framework-b/api/current.txt | 122 ++++++++++++++++++ Vcn/framework-b/api/module-lib-current.txt | 27 ++++ Vcn/framework-b/api/system-current.txt | 22 ++++ .../framework-vcn-jarjar-rules.txt | 2 + ...nnectivityFrameworkInitializerBaklava.java | 116 +++++++++++++++++ .../src/android/net/vcn/VcnManager.java | 8 +- .../src/android/net/vcn/util/LogUtils.java | 2 +- .../net/vcn/util/PersistableBundleUtils.java | 2 +- Vcn/service-b/Android.bp | 53 +++++++- .../android/server/VcnManagementService.java | 66 +++++----- .../src/com/android/server/vcn/TEST_MAPPING | 10 -- .../vcn/TelephonySubscriptionTracker.java | 2 +- .../src/com/android/server/vcn/Vcn.java | 2 +- .../server/vcn/VcnGatewayConnection.java | 4 +- .../server/vcn/VcnNetworkProvider.java | 2 +- .../IpSecPacketLossDetector.java | 2 +- .../UnderlyingNetworkController.java | 2 +- Vcn/tests/unit/Android.bp | 5 +- .../vcn/TelephonySubscriptionTrackerTest.java | 3 +- 22 files changed, 513 insertions(+), 57 deletions(-) create mode 100644 Vcn/flags/Android.bp create mode 100644 Vcn/framework-b/framework-vcn-jarjar-rules.txt create mode 100644 Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java delete mode 100644 Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING diff --git a/Vcn/TEST_MAPPING b/Vcn/TEST_MAPPING index bde88fe9b7..9722a838ab 100644 --- a/Vcn/TEST_MAPPING +++ b/Vcn/TEST_MAPPING @@ -1,4 +1,12 @@ { + "presubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } + ], "postsubmit": [ { "name": "FrameworksVcnTests" diff --git a/Vcn/flags/Android.bp b/Vcn/flags/Android.bp new file mode 100644 index 0000000000..3943c6f7fe --- /dev/null +++ b/Vcn/flags/Android.bp @@ -0,0 +1,38 @@ +// +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_enigma", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +aconfig_declarations { + name: "android.net.vcn.flags-aconfig", + package: "android.net.vcn", + container: "com.android.tethering", + exportable: true, + srcs: [ + "flags.aconfig", + ], +} + +java_aconfig_library { + name: "android.net.vcn.flags-aconfig-java-export", + aconfig_declarations: "android.net.vcn.flags-aconfig", + mode: "exported", + min_sdk_version: "35", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp index 8b010c7f2e..c3121162b7 100644 --- a/Vcn/framework-b/Android.bp +++ b/Vcn/framework-b/Android.bp @@ -19,6 +19,18 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +filegroup { + name: "vcn-utils-platform-sources", + srcs: [ + "src/android/net/vcn/persistablebundleutils/**/*.java", + "src/android/net/vcn/util/**/*.java", + ], + path: "src", + visibility: [ + "//frameworks/base", // For VpnProfile.java and Vpn.java + ], +} + java_defaults { name: "framework-connectivity-b-defaults", sdk_version: "module_current", @@ -27,7 +39,25 @@ java_defaults { srcs: [ "src/**/*.java", + "src/**/*.aidl", ], + + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "app-compat-annotations", + "framework-wifi.stubs.module_lib", + "unsupportedappusage", + ], + static_libs: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", + ], + aidl: { + include_dirs: [ + // For connectivity-framework classes such as Network.aidl, NetworkCapabilities.aidl + "packages/modules/Connectivity/framework/aidl-export", + ], + }, } java_sdk_library { @@ -36,8 +66,35 @@ java_sdk_library { "framework-connectivity-b-defaults", ], + //TODO: b/375213246 Use "framework-connectivity-jarjar-rules" when VCN is + // in mainline + jarjar_rules: "framework-vcn-jarjar-rules.txt", + permitted_packages: [ + "android.net", "android.net.vcn", + "com.android.server.vcn.util", + + ], + api_packages: [ + "android.net", + "android.net.vcn", + ], + + // Allow VCN APIs to reference APIs in IKE and Connectivity + stub_only_libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "framework-connectivity.stubs.module_lib", + ], + + // To use non-jarjard names of utilities such as android.util.IndentingPrintWriter + impl_only_libs: [ + "framework-connectivity-pre-jarjar", + ], + + aconfig_declarations: [ + //TODO:375213246 Use a non-exported flag lib when VCN is in mainline + "android.net.vcn.flags-aconfig-java-export", ], impl_library_visibility: [ @@ -63,5 +120,18 @@ java_sdk_library { "//packages/modules/Wifi/service/tests/wifitests", ], - // TODO: b/375213246 Expose this library to Tethering module + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + +java_library { + name: "framework-connectivity-b-pre-jarjar", + defaults: ["framework-connectivity-b-defaults"], + libs: [ + "framework-connectivity-pre-jarjar", + ], } diff --git a/Vcn/framework-b/api/current.txt b/Vcn/framework-b/api/current.txt index d802177e24..831b74158e 100644 --- a/Vcn/framework-b/api/current.txt +++ b/Vcn/framework-b/api/current.txt @@ -1 +1,123 @@ // Signature format: 2.0 +package android.net.vcn { + + public final class VcnCellUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method public int getCbs(); + method public int getDun(); + method public int getIms(); + method public int getInternet(); + method public int getMms(); + method @NonNull public java.util.Set getOperatorPlmnIds(); + method public int getOpportunistic(); + method public int getRcs(); + method public int getRoaming(); + method @NonNull public java.util.Set getSimSpecificCarrierIds(); + } + + public static final class VcnCellUnderlyingNetworkTemplate.Builder { + ctor public VcnCellUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setCbs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setDun(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setIms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setInternet(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMms(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOperatorPlmnIds(@NonNull java.util.Set); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOpportunistic(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRcs(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRoaming(int); + method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setSimSpecificCarrierIds(@NonNull java.util.Set); + } + + public final class VcnConfig implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Set getGatewayConnectionConfigs(); + method @NonNull public java.util.Set getRestrictedUnderlyingNetworkTransports(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class VcnConfig.Builder { + ctor public VcnConfig.Builder(@NonNull android.content.Context); + method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig); + method @NonNull public android.net.vcn.VcnConfig build(); + method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set); + } + + public final class VcnGatewayConnectionConfig { + method @NonNull public int[] getExposedCapabilities(); + method @NonNull public String getGatewayConnectionName(); + method @IntRange(from=0x500) public int getMaxMtu(); + method public int getMinUdpPort4500NatTimeoutSeconds(); + method @NonNull public long[] getRetryIntervalsMillis(); + method @NonNull public java.util.List getVcnUnderlyingNetworkPriorities(); + method public boolean hasGatewayOption(int); + method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff + field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 + } + + public static final class VcnGatewayConnectionConfig.Builder { + ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); + method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setSafeModeEnabled(boolean); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setVcnUnderlyingNetworkPriorities(@NonNull java.util.List); + } + + public class VcnManager { + method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; + method @NonNull public java.util.List getConfiguredSubscriptionGroups(); + method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); + method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; + method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); + field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 + field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 + field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 + field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 + field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 + field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 + field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 + } + + public abstract static class VcnManager.VcnStatusCallback { + ctor public VcnManager.VcnStatusCallback(); + method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable); + method public abstract void onStatusChanged(int); + } + + public abstract class VcnUnderlyingNetworkTemplate { + method public int getMetered(); + method public int getMinEntryDownstreamBandwidthKbps(); + method public int getMinEntryUpstreamBandwidthKbps(); + method public int getMinExitDownstreamBandwidthKbps(); + method public int getMinExitUpstreamBandwidthKbps(); + field public static final int MATCH_ANY = 0; // 0x0 + field public static final int MATCH_FORBIDDEN = 2; // 0x2 + field public static final int MATCH_REQUIRED = 1; // 0x1 + } + + public final class VcnWifiUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { + method @NonNull public java.util.Set getSsids(); + } + + public static final class VcnWifiUnderlyingNetworkTemplate.Builder { + ctor public VcnWifiUnderlyingNetworkTemplate.Builder(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate build(); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMetered(int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); + method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setSsids(@NonNull java.util.Set); + } + +} + diff --git a/Vcn/framework-b/api/module-lib-current.txt b/Vcn/framework-b/api/module-lib-current.txt index d802177e24..8961b2830f 100644 --- a/Vcn/framework-b/api/module-lib-current.txt +++ b/Vcn/framework-b/api/module-lib-current.txt @@ -1 +1,28 @@ // Signature format: 2.0 +package android.net { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers(); + } + +} + +package android.net.vcn { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder { + ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + } + +} + diff --git a/Vcn/framework-b/api/system-current.txt b/Vcn/framework-b/api/system-current.txt index d802177e24..9c5a67701b 100644 --- a/Vcn/framework-b/api/system-current.txt +++ b/Vcn/framework-b/api/system-current.txt @@ -1 +1,23 @@ // Signature format: 2.0 +package android.net.vcn { + + public class VcnManager { + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); + } + + public static interface VcnManager.VcnNetworkPolicyChangeListener { + method public void onPolicyChanged(); + } + + public final class VcnNetworkPolicyResult implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public boolean isTeardownRequested(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + +} + diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/Vcn/framework-b/framework-vcn-jarjar-rules.txt new file mode 100644 index 0000000000..757043bdbb --- /dev/null +++ b/Vcn/framework-b/framework-vcn-jarjar-rules.txt @@ -0,0 +1,2 @@ +rule android.net.vcn.persistablebundleutils.** android.net.vcn.module.repackaged.persistablebundleutils.@1 +rule android.net.vcn.util.** android.net.vcn.module.repackaged.util.@1 \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java new file mode 100644 index 0000000000..1f0fa92d79 --- /dev/null +++ b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; + +import android.annotation.FlaggedApi; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.vcn.IVcnManagementService; +import android.net.vcn.VcnManager; +import android.os.Build; +import android.os.SystemProperties; + +/** + * Class for performing registration for VCN service. + * + * @hide + */ +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerBaklava { + /** + * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link + * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers + * that depend on them. If the feature is missing, {@link Context#getSystemService} will return + * null. + * + *

    This change is specific to VcnManager. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + /** + * The corresponding vendor API for Android V + * + *

    Starting with Android V, the vendor API format has switched to YYYYMM. + * + * @see Vendor API + * level + */ + private static final int VENDOR_API_FOR_ANDROID_V = 202404; + + private ConnectivityFrameworkInitializerBaklava() {} + + // Suppressing AndroidFrameworkCompatChange because we're querying vendor + // partition SDK level, not application's target SDK version (which BTW we + // also check through Compatibility framework a few lines below). + @Nullable + private static String getVcnFeatureDependency() { + // Check SDK version of the client app. Apps targeting pre-V SDK might + // have not checked for existence of these features. + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + return null; + } + + // Check SDK version of the vendor partition. Pre-V devices might have + // incorrectly under-declared telephony features. + final int vendorApiLevel = + SystemProperties.getInt( + "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); + if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) { + return PackageManager.FEATURE_TELEPHONY; + } else { + return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; + } + } + + /** + * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return + * a VcnManager. + * + * @throws IllegalStateException if this is called anywhere besides {@link + * SystemServiceRegistry}. + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + VcnManager.VCN_MANAGEMENT_SERVICE_STRING, + VcnManager.class, + (context, serviceBinder) -> { + final String telephonyFeatureToCheck = getVcnFeatureDependency(); + if (telephonyFeatureToCheck != null + && !context.getPackageManager() + .hasSystemFeature(telephonyFeatureToCheck)) { + return null; + } + IVcnManagementService service = + IVcnManagementService.Stub.asInterface(serviceBinder); + return new VcnManager(context, service); + }); + } +} diff --git a/Vcn/framework-b/src/android/net/vcn/VcnManager.java b/Vcn/framework-b/src/android/net/vcn/VcnManager.java index f275714e2c..594bbb8a20 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnManager.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnManager.java @@ -334,7 +334,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnUnderlyingNetworkPolicyListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already * registered * @hide @@ -423,7 +423,7 @@ public class VcnManager { * @param executor the Executor that will be used for invoking all calls to the specified * Listener * @param listener the VcnNetworkPolicyChangeListener to be added - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already * registered * @hide @@ -455,7 +455,7 @@ public class VcnManager { *

    If the specified listener is not currently registered, this is a no-op. * * @param listener the VcnNetworkPolicyChangeListener that will be removed - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @hide */ @SystemApi @@ -489,7 +489,7 @@ public class VcnManager { * policy result for this Network. * @param linkProperties the LinkProperties to be used in determining the Network policy result * for this Network. - * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws SecurityException if the caller does not have the required permission * @return the {@link VcnNetworkPolicyResult} to be used for this Network. * @hide */ diff --git a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java index 7f7f852716..742aa761e6 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/LogUtils.java @@ -19,7 +19,7 @@ package android.net.vcn.util; import android.annotation.Nullable; import android.os.ParcelUuid; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; /** @hide */ public class LogUtils { diff --git a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java index 4dc42c7827..8a687d8c59 100644 --- a/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java +++ b/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.os.ParcelUuid; import android.os.PersistableBundle; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 03ef4e67af..26d8397494 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -32,6 +32,33 @@ filegroup { visibility: ["//frameworks/base/services/core"], } +// Do not static include this lib in VCN because these files exist in +// both service-connectivity.jar and framework.jar +// TODO: b/374174952 After VCN moves to Connectivity/ and the modularization is done +// this lib can be removed and "service-connectivity-b-pre-jarjar" can include +// "service-connectivity-pre-jarjar" +java_library { + name: "connectivity-utils-service-vcn-internal", + sdk_version: "module_current", + min_sdk_version: "30", + srcs: [ + ":framework-connectivity-shared-srcs", + ], + libs: [ + "framework-annotations-lib", + "unsupportedappusage", + ], + visibility: [ + "//visibility:private", + ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], +} + java_library { name: "service-connectivity-b-pre-jarjar", sdk_version: "system_server_current", @@ -42,8 +69,32 @@ java_library { "src/**/*.java", ], - // TODO: b/375213246 Expose this library to Tethering module + libs: [ + "android.net.ipsec.ike.stubs.module_lib", + "connectivity-utils-service-vcn-internal", + "framework-annotations-lib", + "framework-connectivity-pre-jarjar", + "framework-connectivity-t-pre-jarjar", + "framework-connectivity-b-pre-jarjar", + "framework-wifi.stubs.module_lib", + "modules-utils-statemachine", + "unsupportedappusage", + ], + + // TODO: b/374174952 Dynamically include these libs when VCN + // modularization is released + static_libs: [ + "net-utils-service-vcn", + "modules-utils-handlerexecutor", + ], + visibility: [ "//frameworks/base/services", ], + apex_available: [ + // TODO: b/374174952 Remove it when VCN modularization is released + "//apex_available:platform", + + "com.android.tethering", + ], } diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index a45b715cca..26db6a988e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -86,6 +86,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.HandlerUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.PermissionUtils; import com.android.server.vcn.TelephonySubscriptionTracker; @@ -1332,41 +1333,46 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| "); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell. - mHandler.runWithScissors(() -> { - mNetworkProvider.dump(pw); - pw.println(); + HandlerUtils.runWithScissorsForDump( + mHandler, + () -> { + mNetworkProvider.dump(pw); + pw.println(); - mTrackingNetworkCallback.dump(pw); - pw.println(); + mTrackingNetworkCallback.dump(pw); + pw.println(); - synchronized (mLock) { - mLastSnapshot.dump(pw); - pw.println(); + synchronized (mLock) { + mLastSnapshot.dump(pw); + pw.println(); - pw.println("mConfigs:"); - pw.increaseIndent(); - for (Entry entry : mConfigs.entrySet()) { - pw.println(entry.getKey() + ": " - + entry.getValue().getProvisioningPackageName()); - } - pw.decreaseIndent(); - pw.println(); + pw.println("mConfigs:"); + pw.increaseIndent(); + for (Entry entry : mConfigs.entrySet()) { + pw.println( + entry.getKey() + + ": " + + entry.getValue().getProvisioningPackageName()); + } + pw.decreaseIndent(); + pw.println(); - pw.println("mVcns:"); - pw.increaseIndent(); - for (Vcn vcn : mVcns.values()) { - vcn.dump(pw); - } - pw.decreaseIndent(); - pw.println(); - } + pw.println("mVcns:"); + pw.increaseIndent(); + for (Vcn vcn : mVcns.values()) { + vcn.dump(pw); + } + pw.decreaseIndent(); + pw.println(); + } - pw.println("Local log:"); - pw.increaseIndent(); - LOCAL_LOG.dump(pw); - pw.decreaseIndent(); - pw.println(); - }, DUMP_TIMEOUT_MILLIS); + pw.println("Local log:"); + pw.increaseIndent(); + LOCAL_LOG.dump(pw); + pw.decreaseIndent(); + pw.println(); + }, + DUMP_TIMEOUT_MILLIS); } // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService diff --git a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING b/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING deleted file mode 100644 index 5b04d884fc..0000000000 --- a/Vcn/service-b/src/com/android/server/vcn/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "FrameworksVcnTests" - }, - { - "name": "CtsVcnTestCases" - } - ] -} \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index 154897eece..b448f7595b 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -29,7 +29,6 @@ import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -46,6 +45,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.ArrayList; import java.util.Collections; diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 95acb107fd..2524d0eeda 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -40,7 +40,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.provider.Settings; @@ -53,6 +52,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 77bda9dc6b..e50fc3a6e8 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -45,6 +45,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.IpSecManager.IpSecTunnelInterface; +import android.net.IpSecManager.PolicyDirection; import android.net.IpSecManager.ResourceUnavailableException; import android.net.IpSecTransform; import android.net.LinkAddress; @@ -59,7 +60,6 @@ import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; import android.net.Uri; -import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; @@ -83,7 +83,6 @@ import android.net.vcn.util.MtuUtils; import android.net.vcn.util.OneWayBoolean; import android.net.wifi.WifiInfo; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; import android.os.PowerManager; @@ -101,6 +100,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController; diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 78ff432f54..4552f509b5 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -33,7 +33,6 @@ import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.vcn.VcnGatewayConnectionConfig; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.util.ArraySet; import android.util.IndentingPrintWriter; @@ -41,6 +40,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import java.util.Objects; import java.util.Set; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index e6a1ff9675..72de61363d 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -32,12 +32,12 @@ import android.net.IpSecTransformState; import android.net.Network; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.OutcomeReceiver; import android.os.PowerManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.VcnContext; import java.lang.annotation.ElementType; diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index f7a564ad52..29a0762f5f 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -41,7 +41,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.util.LogUtils; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; @@ -52,6 +51,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.modules.utils.HandlerExecutor; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; diff --git a/Vcn/tests/unit/Android.bp b/Vcn/tests/unit/Android.bp index b16ba15a68..51a300bff7 100644 --- a/Vcn/tests/unit/Android.bp +++ b/Vcn/tests/unit/Android.bp @@ -14,21 +14,24 @@ package { android_test { name: "FrameworksVcnTests", + // For access hidden connectivity methods in tests + defaults: ["framework-connectivity-test-defaults"], srcs: [ "java/**/*.java", "java/**/*.kt", ], platform_apis: true, - defaults: ["framework-connectivity-test-defaults"], test_suites: ["device-tests"], certificate: "platform", static_libs: [ + "android.net.vcn.flags-aconfig-java-export", "androidx.test.rules", "frameworks-base-testutils", "framework-protos", "mockito-target-minus-junit4", "net-tests-utils", "platform-test-annotations", + "service-connectivity-b-pre-jarjar", "services.core", "service-connectivity-tiramisu-pre-jarjar", "flag-junit", diff --git a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index b999475cba..77f82f0d8c 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -55,7 +55,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.test.TestLooper; @@ -72,6 +71,8 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.HandlerExecutor; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; From 865c0e7852df13bf97392abf78e285219fa59c44 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 25 Oct 2024 14:40:14 -0700 Subject: [PATCH 0497/1057] Conditionally remove VCN jars from non-updatable platform When the build system flag RELEASE_MOVE_VCN_TO_MAINLINE is true, VCN framework and service jars will be built into Tethering module. Otherwise, VCN framework jar will be directly installed on the device and the service jar will be included into the platform services.jar Bug: 375213246 Test: atest CtsVcnTestCases && atest FrameworksVcnTests; verified with the flag on and off Flag: RELEASE_MOVE_VCN_TO_MAINLINE Change-Id: If2651f1ede34220172c419f8bf4afb0fe09c0789 --- Vcn/flags/Android.bp | 14 +++ Vcn/framework-b/Android.bp | 98 ++++++++++++++----- .../framework-vcn-jarjar-rules-platform.txt | 2 + .../framework-vcn-jarjar-rules.txt | 4 +- ...nnectivityFrameworkInitializerBaklava.java | 24 ++--- Vcn/service-b/Android.bp | 57 +++++++---- .../service-vcn-platform-jarjar-rules.txt | 5 + .../ConnectivityServiceInitializerB.java | 4 + .../android/server/VcnManagementService.java | 9 +- .../vcn/TelephonySubscriptionTracker.java | 4 + .../src/com/android/server/vcn/Vcn.java | 4 + .../server/vcn/VcnGatewayConnection.java | 9 ++ .../server/vcn/VcnNetworkProvider.java | 4 + .../IpSecPacketLossDetector.java | 4 + .../routeselection/NetworkMetricMonitor.java | 4 + .../NetworkPriorityClassifier.java | 4 + .../UnderlyingNetworkController.java | 4 + .../UnderlyingNetworkEvaluator.java | 4 + 18 files changed, 197 insertions(+), 61 deletions(-) create mode 100644 Vcn/framework-b/framework-vcn-jarjar-rules-platform.txt create mode 100644 Vcn/service-b/service-vcn-platform-jarjar-rules.txt diff --git a/Vcn/flags/Android.bp b/Vcn/flags/Android.bp index 3943c6f7fe..8d09fdbfa3 100644 --- a/Vcn/flags/Android.bp +++ b/Vcn/flags/Android.bp @@ -29,10 +29,24 @@ aconfig_declarations { ], } +// TODO: b/374174952 Remove this library when VCN modularization is done java_aconfig_library { name: "android.net.vcn.flags-aconfig-java-export", aconfig_declarations: "android.net.vcn.flags-aconfig", mode: "exported", min_sdk_version: "35", defaults: ["framework-minus-apex-aconfig-java-defaults"], + apex_available: [ + "//apex_available:platform", + ], +} + +java_aconfig_library { + name: "android.net.vcn.flags-aconfig-java", + aconfig_declarations: "android.net.vcn.flags-aconfig", + min_sdk_version: "35", + defaults: ["framework-minus-apex-aconfig-java-defaults"], + apex_available: [ + "com.android.tethering", + ], } diff --git a/Vcn/framework-b/Android.bp b/Vcn/framework-b/Android.bp index c3121162b7..edb22c0e7a 100644 --- a/Vcn/framework-b/Android.bp +++ b/Vcn/framework-b/Android.bp @@ -32,9 +32,9 @@ filegroup { } java_defaults { - name: "framework-connectivity-b-defaults", + name: "framework-connectivity-b-defaults-base", sdk_version: "module_current", - min_sdk_version: "35", // TODO: Make it Android 25Q2 when this is included in mainline + defaults: ["framework-module-defaults"], // This is a boot jar srcs: [ @@ -44,14 +44,10 @@ java_defaults { libs: [ "android.net.ipsec.ike.stubs.module_lib", - "app-compat-annotations", "framework-wifi.stubs.module_lib", "unsupportedappusage", ], - static_libs: [ - //TODO:375213246 Use a non-exported flag lib when VCN is in mainline - "android.net.vcn.flags-aconfig-java-export", - ], + aidl: { include_dirs: [ // For connectivity-framework classes such as Network.aidl, NetworkCapabilities.aidl @@ -60,16 +56,83 @@ java_defaults { }, } +soong_config_module_type { + name: "framework_connectivity_b_defaults_soong_config", + module_type: "java_defaults", + config_namespace: "ANDROID", + bool_variables: [ + "is_vcn_in_mainline", + ], + properties: [ + "min_sdk_version", + "static_libs", + "apex_available", + ], +} + +framework_connectivity_b_defaults_soong_config { + name: "framework-connectivity-b-defaults", + defaults: [ + "framework-connectivity-b-defaults-base", + ], + soong_config_variables: { + is_vcn_in_mainline: { + //TODO: b/380155299 Make it Baklava when aidl tool can understand it + min_sdk_version: "current", + static_libs: ["android.net.vcn.flags-aconfig-java"], + apex_available: ["com.android.tethering"], + + conditions_default: { + min_sdk_version: "35", + static_libs: ["android.net.vcn.flags-aconfig-java-export"], + apex_available: ["//apex_available:platform"], + }, + }, + }, +} + +soong_config_module_type { + name: "framework_connectivity_b_java_sdk_library_defaults_soong_config", + module_type: "java_defaults", + config_namespace: "ANDROID", + bool_variables: [ + "is_vcn_in_mainline", + ], + properties: [ + "aconfig_declarations", + "jarjar_rules", + ], +} + +framework_connectivity_b_java_sdk_library_defaults_soong_config { + name: "framework-connectivity-b-java-sdk-library-defaults", + soong_config_variables: { + is_vcn_in_mainline: { + aconfig_declarations: ["android.net.vcn.flags-aconfig-java"], + + // TODO: b/375213246 Use the connectivity jarjar rule generator to create the + // jarjar rules. In the end state, use "framework-connectivity-jarjar-rules" + // after VCN code is moved to the Connectivity folder + jarjar_rules: "framework-vcn-jarjar-rules.txt", + + conditions_default: { + aconfig_declarations: ["android.net.vcn.flags-aconfig-java-export"], + + // Use "android.net.connectivity" as prefix would trigger + // "Hidden API flags are inconsistent" build error + jarjar_rules: "framework-vcn-jarjar-rules-platform.txt", + }, + }, + }, +} + java_sdk_library { name: "framework-connectivity-b", defaults: [ "framework-connectivity-b-defaults", + "framework-connectivity-b-java-sdk-library-defaults", ], - //TODO: b/375213246 Use "framework-connectivity-jarjar-rules" when VCN is - // in mainline - jarjar_rules: "framework-vcn-jarjar-rules.txt", - permitted_packages: [ "android.net", "android.net.vcn", @@ -92,11 +155,6 @@ java_sdk_library { "framework-connectivity-pre-jarjar", ], - aconfig_declarations: [ - //TODO:375213246 Use a non-exported flag lib when VCN is in mainline - "android.net.vcn.flags-aconfig-java-export", - ], - impl_library_visibility: [ // Using for test only "//cts/tests/netlegacy22.api", @@ -120,17 +178,13 @@ java_sdk_library { "//packages/modules/Wifi/service/tests/wifitests", ], - apex_available: [ - // TODO: b/374174952 Remove it when VCN modularization is released - "//apex_available:platform", - - "com.android.tethering", - ], + visibility: ["//packages/modules/Connectivity:__subpackages__"], } java_library { name: "framework-connectivity-b-pre-jarjar", defaults: ["framework-connectivity-b-defaults"], + installable: false, libs: [ "framework-connectivity-pre-jarjar", ], diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules-platform.txt b/Vcn/framework-b/framework-vcn-jarjar-rules-platform.txt new file mode 100644 index 0000000000..757043bdbb --- /dev/null +++ b/Vcn/framework-b/framework-vcn-jarjar-rules-platform.txt @@ -0,0 +1,2 @@ +rule android.net.vcn.persistablebundleutils.** android.net.vcn.module.repackaged.persistablebundleutils.@1 +rule android.net.vcn.util.** android.net.vcn.module.repackaged.util.@1 \ No newline at end of file diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/Vcn/framework-b/framework-vcn-jarjar-rules.txt index 757043bdbb..7e27b24f74 100644 --- a/Vcn/framework-b/framework-vcn-jarjar-rules.txt +++ b/Vcn/framework-b/framework-vcn-jarjar-rules.txt @@ -1,2 +1,2 @@ -rule android.net.vcn.persistablebundleutils.** android.net.vcn.module.repackaged.persistablebundleutils.@1 -rule android.net.vcn.util.** android.net.vcn.module.repackaged.util.@1 \ No newline at end of file +rule android.net.vcn.persistablebundleutils.** android.net.connectivity.android.net.vcn.persistablebundleutils.@1 +rule android.net.vcn.util.** android.net.connectivity.android.net.vcn.util.@1 \ No newline at end of file diff --git a/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java index 1f0fa92d79..de22ca6848 100644 --- a/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java +++ b/Vcn/framework-b/src/android/net/ConnectivityFrameworkInitializerBaklava.java @@ -23,8 +23,6 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.SystemServiceRegistry; import android.compat.Compatibility; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.content.Context; import android.content.pm.PackageManager; import android.net.vcn.IVcnManagementService; @@ -40,17 +38,15 @@ import android.os.SystemProperties; @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class ConnectivityFrameworkInitializerBaklava { - /** - * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link - * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers - * that depend on them. If the feature is missing, {@link Context#getSystemService} will return - * null. - * - *

    This change is specific to VcnManager. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) - private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016; + + // This is a copy of TelephonyFrameworkInitializer.ENABLE_CHECKING_TELEPHONY_FEATURES. This + // ChangeId will replace ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN to gate VcnManager + // feature flag enforcement. + // This replacement is safe because both ChangeIds have been enabled since Android V and serve + // the same purpose: enforcing telephony feature flag checks before using telephony-based + // features. This also simplifies VCN modularization by avoiding the need to handle different + // states, such as: SDK < B vs. SDK >= B; VCN in platform vs. VCN in the apex. + private static final long ENABLE_CHECKING_TELEPHONY_FEATURES = 330583731; /** * The corresponding vendor API for Android V @@ -71,7 +67,7 @@ public final class ConnectivityFrameworkInitializerBaklava { private static String getVcnFeatureDependency() { // Check SDK version of the client app. Apps targeting pre-V SDK might // have not checked for existence of these features. - if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) { + if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES)) { return null; } diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index c1a1ee7875..1370b0678c 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -32,11 +32,9 @@ filegroup { visibility: ["//frameworks/base/services/core"], } -// Do not static include this lib in VCN because these files exist in -// both service-connectivity.jar and framework.jar -// TODO: b/374174952 After VCN moves to Connectivity/ and the modularization is done -// this lib can be removed and "service-connectivity-b-pre-jarjar" can include -// "service-connectivity-pre-jarjar" +// TODO: b/374174952 This library is only used in "service-connectivity-b-platform" +// After VCN moves to Connectivity/ and the modularization is done, this lib and +// "service-connectivity-b-platform" can both be removed java_library { name: "connectivity-utils-service-vcn-internal", sdk_version: "module_current", @@ -48,30 +46,30 @@ java_library { "framework-annotations-lib", "unsupportedappusage", ], - visibility: [ - "//visibility:private", - ], - apex_available: [ - // TODO: b/374174952 Remove it when VCN modularization is released - "//apex_available:platform", + visibility: ["//visibility:private"], +} - "com.android.tethering", +filegroup { + name: "service-vcn-sources", + srcs: ["src/**/*.java"], + path: "src", + visibility: [ + "//packages/modules/Connectivity/service-b", ], } -java_library { - name: "service-connectivity-b-pre-jarjar", - sdk_version: "system_server_current", - min_sdk_version: "35", // TODO: Make it Android 25Q2 when this is included in mainline +// This java_defaults will be used for "service-connectivity-b-platform" and +// "service-connectivity-b-pre-jarjar" +java_defaults { + name: "service-connectivity-b-pre-jarjar-defaults", defaults: ["framework-system-server-module-defaults"], // This is a system server jar srcs: [ - "src/**/*.java", + ":service-vcn-sources", ], libs: [ "android.net.ipsec.ike.stubs.module_lib", - "connectivity-utils-service-vcn-internal", "framework-annotations-lib", "framework-connectivity-pre-jarjar", "framework-connectivity-t-pre-jarjar", @@ -89,13 +87,30 @@ java_library { "modules-utils-handlerexecutor", ], + defaults_visibility: [ + "//packages/modules/Connectivity/service-b", + ], +} + +// This library is only used to be included into services.jar when the build system +// flag RELEASE_MOVE_VCN_TO_MAINLINE is disabled. When the flag is enabled, a module +// version of this library will be included in Tethering module +java_library { + name: "service-connectivity-b-platform", + defaults: ["service-connectivity-b-pre-jarjar-defaults"], + static_libs: ["connectivity-utils-service-vcn-internal"], + + sdk_version: "system_server_current", + min_sdk_version: "35", + + // TODO (b/374174952 ): This file is for jarjaring files in + // "connectivity-utils-service-vcn-internal". + jarjar_rules: "service-vcn-platform-jarjar-rules.txt", + visibility: [ "//frameworks/base/services", ], apex_available: [ - // TODO: b/374174952 Remove it when VCN modularization is released "//apex_available:platform", - - "com.android.tethering", ], } diff --git a/Vcn/service-b/service-vcn-platform-jarjar-rules.txt b/Vcn/service-b/service-vcn-platform-jarjar-rules.txt new file mode 100644 index 0000000000..36307277b4 --- /dev/null +++ b/Vcn/service-b/service-vcn-platform-jarjar-rules.txt @@ -0,0 +1,5 @@ +rule android.util.IndentingPrintWriter android.net.vcn.module.repackaged.android.util.IndentingPrintWriter +rule android.util.LocalLog android.net.vcn.module.repackaged.android.util.LocalLog +rule com.android.internal.util.IndentingPrintWriter android.net.vcn.module.repackaged.com.android.internal.util.IndentingPrintWriter +rule com.android.internal.util.MessageUtils android.net.vcn.module.repackaged.com.android.internal.util.MessageUtils +rule com.android.internal.util.WakeupMessage android.net.vcn.module.repackaged.com.android.internal.util.WakeupMessage \ No newline at end of file diff --git a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java index 02c8ce4f29..81c7edf4ad 100644 --- a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java +++ b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java @@ -16,7 +16,9 @@ package com.android.server; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.util.Log; import com.android.tools.r8.keepanno.annotations.KeepItemKind; @@ -30,6 +32,8 @@ import com.android.tools.r8.keepanno.annotations.UsedByReflection; // Without this annotation, this class will be treated as unused class and be removed during build // time. @UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS) +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public final class ConnectivityServiceInitializerB extends SystemService { private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName(); private final VcnManagementService mVcnManagementService; diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index 26db6a988e..c9a99d729e 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -37,6 +37,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -164,6 +165,8 @@ import java.util.concurrent.TimeUnit; * @hide */ // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; @@ -297,8 +300,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } - // Package-visibility for SystemServer to create instances. - static VcnManagementService create(@NonNull Context context) { + /** Called by ConnectivityServiceInitializerB to create instances. */ + // VcnManagementService will be jarjared but ConnectivityServiceInitializerB will not. Thus this + // method needs to be public for ConnectivityServiceInitializerB to access + public static VcnManagementService create(@NonNull Context context) { return new VcnManagementService(context, new Dependencies()); } diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index b448f7595b..b04e25dff2 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -22,12 +22,14 @@ import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; +import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -77,6 +79,8 @@ import java.util.Set; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private static final String TAG = TelephonySubscriptionTracker.class.getSimpleName(); private static final boolean LOG_DBG = false; // STOPSHIP if true diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 2524d0eeda..369ef6ae6a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -29,6 +29,7 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.content.ContentResolver; import android.database.ContentObserver; import android.net.NetworkCapabilities; @@ -39,6 +40,7 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.util.LogUtils; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; @@ -75,6 +77,8 @@ import java.util.Set; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index e50fc3a6e8..300b80f942 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -37,6 +37,8 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; @@ -82,6 +84,7 @@ import android.net.vcn.util.LogUtils; import android.net.vcn.util.MtuUtils; import android.net.vcn.util.OneWayBoolean; import android.net.wifi.WifiInfo; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; @@ -171,6 +174,8 @@ import java.util.function.Consumer; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); @@ -2942,6 +2947,10 @@ public class VcnGatewayConnection extends StateMachine { * *

    Synchronize this action to minimize locking around WakeLock use. */ + // WakelockTimeout suppressed because the time the wake lock is needed for is unknown. The + // wakelock is only acquired when a Message is sent to this state machine and will be + // released when the message is processed or the state machin quits + @SuppressLint("WakelockTimeout") public synchronized void acquire() { mImpl.acquire(); } diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 4552f509b5..99c848f53c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; +import android.annotation.TargetApi; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; @@ -32,6 +33,7 @@ import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.ArraySet; @@ -54,6 +56,8 @@ import java.util.concurrent.Executor; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class VcnNetworkProvider extends NetworkProvider { private static final String TAG = VcnNetworkProvider.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 72de61363d..6467af4355 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -23,6 +23,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,6 +32,7 @@ import android.net.ConnectivityManager; import android.net.IpSecTransformState; import android.net.Network; import android.net.vcn.VcnManager; +import android.os.Build; import android.os.Handler; import android.os.OutcomeReceiver; import android.os.PowerManager; @@ -59,6 +61,8 @@ import java.util.concurrent.TimeUnit; * *

    This class is flag gated by "network_metric_monitor" and "ipsec_tramsform_state" */ +// TODO(b/374174952) Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 86cee554be..14853440a1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -22,9 +22,11 @@ import static com.android.server.VcnManagementService.LOCAL_LOG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.net.IpSecTransform; import android.net.IpSecTransformState; import android.net.Network; +import android.os.Build; import android.os.OutcomeReceiver; import android.util.CloseGuard; import android.util.Slog; @@ -42,6 +44,8 @@ import java.util.concurrent.Executor; * *

    This class is flag gated by "network_metric_monitor" */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public abstract class NetworkMetricMonitor implements AutoCloseable { private static final String TAG = NetworkMetricMonitor.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 79c4116d0c..705141f3f1 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -29,12 +29,14 @@ import static com.android.server.VcnManagementService.LOCAL_LOG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; +import android.os.Build; import android.os.ParcelUuid; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -50,6 +52,8 @@ import java.util.Map; import java.util.Set; /** @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) class NetworkPriorityClassifier { @NonNull private static final String TAG = NetworkPriorityClassifier.class.getSimpleName(); /** diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 29a0762f5f..bc552e7e6a 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -28,6 +28,7 @@ import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.ge import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.IpSecTransform; @@ -40,6 +41,7 @@ import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.util.LogUtils; +import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; import android.telephony.TelephonyCallback; @@ -73,6 +75,8 @@ import java.util.TreeSet; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class UnderlyingNetworkController { @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 30f4ed1b9f..776931bad7 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -22,12 +22,14 @@ import static com.android.server.VcnManagementService.LOCAL_LOG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; import android.util.IndentingPrintWriter; @@ -50,6 +52,8 @@ import java.util.concurrent.TimeUnit; * * @hide */ +// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization +@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class UnderlyingNetworkEvaluator { private static final String TAG = UnderlyingNetworkEvaluator.class.getSimpleName(); From 2cfa0893fd5137621f95a75c89d17c0718feaea2 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 11 Dec 2024 11:35:43 -0800 Subject: [PATCH 0498/1057] Add CTS for VcnTransportInfo Bug: 376553318 Test: atest CtsVcnTestCases Flag: EXEMPT test code Change-Id: Idc44d76783e5d2918ee598bfd0a83db46512024e --- .../net/vcn/cts/VcnTransportInfoTest.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/VcnTransportInfoTest.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnTransportInfoTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTransportInfoTest.java new file mode 100644 index 0000000000..3e6b350a33 --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnTransportInfoTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn.cts; + +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; + +import static org.junit.Assert.assertEquals; + +import android.net.vcn.Flags; +import android.net.vcn.VcnTransportInfo; +import android.os.Parcel; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RequiresFlagsEnabled(Flags.FLAG_MAINLINE_VCN_MODULE_API) +@RunWith(AndroidJUnit4.class) +public class VcnTransportInfoTest extends VcnTestBase { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + private static final int NAT_TIMEOUT_SECONDS = 600; + + @Test + public void testBuilderAndGettersWithMinimumSet() { + final VcnTransportInfo transportInfo = new VcnTransportInfo.Builder().build(); + + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET, + transportInfo.getMinUdpPort4500NatTimeoutSeconds()); + + assertEquals(REDACT_FOR_NETWORK_SETTINGS, transportInfo.getApplicableRedactions()); + assertEquals(transportInfo, transportInfo.makeCopy(REDACT_FOR_NETWORK_SETTINGS)); + } + + @Test + public void testBuilderAndGettersWithNatTimeout() { + final VcnTransportInfo transportInfo = + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(NAT_TIMEOUT_SECONDS) + .build(); + + assertEquals(NAT_TIMEOUT_SECONDS, transportInfo.getMinUdpPort4500NatTimeoutSeconds()); + } + + @Test + public void testParcelUnparcel() { + final VcnTransportInfo transportInfo = + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(NAT_TIMEOUT_SECONDS) + .build(); + + final Parcel parcel = Parcel.obtain(); + transportInfo.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + + assertEquals(transportInfo, VcnTransportInfo.CREATOR.createFromParcel(parcel)); + } +} From b0c0618d933280ad37a2331685f0394e1901145c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 11 Dec 2024 13:34:21 -0800 Subject: [PATCH 0499/1057] Add CTS for ConnectivityFrameworkInitializerBaklava Bug: 376553318 Test: atest CtsVcnTestCases:ConnectivityFrameworkInitializerBaklavaTest Flag: EXEMPT; test code Change-Id: I8005fa20266152e824b4685db4f8dbed9e2a006b --- ...tivityFrameworkInitializerBaklavaTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Vcn/tests/cts/src/android/net/vcn/cts/ConnectivityFrameworkInitializerBaklavaTest.java diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/ConnectivityFrameworkInitializerBaklavaTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/ConnectivityFrameworkInitializerBaklavaTest.java new file mode 100644 index 0000000000..0bc38b51fc --- /dev/null +++ b/Vcn/tests/cts/src/android/net/vcn/cts/ConnectivityFrameworkInitializerBaklavaTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn.cts; + +import static org.junit.Assert.assertThrows; + +import android.net.ConnectivityFrameworkInitializerBaklava; +import android.net.vcn.Flags; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RequiresFlagsEnabled(Flags.FLAG_MAINLINE_VCN_MODULE_API) +@RunWith(AndroidJUnit4.class) +public class ConnectivityFrameworkInitializerBaklavaTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + /** + * ConnectivityFrameworkInitializerBaklava.registerServiceWrappers() should only be called by + * SystemServiceRegistry during boot up. Calling this API at any other time should throw an + * exception. + */ + @Test + public void testRegisterServiceWrappers() { + assertThrows( + IllegalStateException.class, + ConnectivityFrameworkInitializerBaklava::registerServiceWrappers); + } +} From 093bdee33848a6b7081868c24dce21b54a8792b1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 16 Dec 2024 11:25:55 -0800 Subject: [PATCH 0500/1057] Add documentations for VcnTransportInfo#makeCopy Bug: 384055633 Test: presubmit Flag: EXEMPT documentation changes Change-Id: I87195ad977bdae93b3e0e283add0904d38fcef71 --- .../src/android/net/vcn/VcnTransportInfo.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 3638429f33..a760b12ac8 100644 --- a/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -161,7 +161,14 @@ public final class VcnTransportInfo implements TransportInfo, Parcelable { return 0; } - /** @hide */ + /** + * Create a copy of a {@link VcnTransportInfo} with some fields redacted based on the + * permissions held by the receiving app. + * + * @param redactions bitmask of redactions that needs to be performed on this instance. + * @return the copy of this instance with the necessary redactions. + * @hide + */ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override From 39b842acfa6bf6388097bfc4de2214ba01d1c0e1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 2 Jan 2025 13:44:50 -0800 Subject: [PATCH 0501/1057] Stop statically including IndentingPrintWriter in VCN service VCN service depends on LocalLog.java and WakeupMessage.java. Previously VCN service will statically include framework-connectivity-shared-srcs filegroup that has the two required classes. To avoid name class conflicts, all classes in this filegroup need to be jarjared. As results, VCN service will use a jarjared IndentingPrintWriter. During dumpsys, VcnManagementService#dump will create a IndentingPrintWriter and pass it to VcnUnderlyingNetworkTemplate#dump. Then because VcnUnderlyingNetworkTemplate fails to recognize the jarjared class, it will throw NoSuchMethodError. This issue only exists when VCN is in the platform. When VCN is built into Tethering module, a different build architecture is used and this issue will be gone. This patch fixes the NoSuchMethodError issue by creating temporary copies of LocalLog and WakeupMessage and updating VCN service to statically include them. When VCN modularization is fully done, these two copies can be removed Bug: 386225194 Test: atest CtsVcnTestCases && atest FrameworksVcnTests Test: adb dumpsys vcn_management Flag: EXEMPT; low risk and small scope bug fix Change-Id: Ie5c099ac04133093c23f8ef6181bab08d1bf8e4b --- Vcn/service-b/Android.bp | 4 +- .../service-utils/android/util/LocalLog.java | 148 ++++++++++++++++++ .../android/internal/util/WakeupMessage.java | 142 +++++++++++++++++ .../service-vcn-platform-jarjar-rules.txt | 3 - 4 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 Vcn/service-b/service-utils/android/util/LocalLog.java create mode 100644 Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java diff --git a/Vcn/service-b/Android.bp b/Vcn/service-b/Android.bp index 1370b0678c..97574e6e35 100644 --- a/Vcn/service-b/Android.bp +++ b/Vcn/service-b/Android.bp @@ -39,9 +39,7 @@ java_library { name: "connectivity-utils-service-vcn-internal", sdk_version: "module_current", min_sdk_version: "30", - srcs: [ - ":framework-connectivity-shared-srcs", - ], + srcs: ["service-utils/**/*.java"], libs: [ "framework-annotations-lib", "unsupportedappusage", diff --git a/Vcn/service-b/service-utils/android/util/LocalLog.java b/Vcn/service-b/service-utils/android/util/LocalLog.java new file mode 100644 index 0000000000..5955d930aa --- /dev/null +++ b/Vcn/service-b/service-utils/android/util/LocalLog.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.SystemClock; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; + +/** + * @hide + */ +// Exported to Mainline modules; cannot use annotations +// @android.ravenwood.annotation.RavenwoodKeepWholeClass +// TODO: b/374174952 This is an exact copy of frameworks/base/core/java/android/util/LocalLog.java. +// This file is only used in "service-connectivity-b-platform" before the VCN modularization flag +// is fully ramped. When the flag is fully ramped and the development is finalized, this file can +// be removed. +public final class LocalLog { + + private final Deque mLog; + private final int mMaxLines; + + /** + * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log + * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is + * useful when logging behavior that modifies device time zone or system clock. + */ + private final boolean mUseLocalTimestamps; + + @UnsupportedAppUsage + public LocalLog(int maxLines) { + this(maxLines, true /* useLocalTimestamps */); + } + + public LocalLog(int maxLines, boolean useLocalTimestamps) { + mMaxLines = Math.max(0, maxLines); + mLog = new ArrayDeque<>(mMaxLines); + mUseLocalTimestamps = useLocalTimestamps; + } + + @UnsupportedAppUsage + public void log(String msg) { + if (mMaxLines <= 0) { + return; + } + final String logLine; + if (mUseLocalTimestamps) { + logLine = LocalDateTime.now() + " - " + msg; + } else { + logLine = Duration.ofMillis(SystemClock.elapsedRealtime()) + + " / " + Instant.now() + " - " + msg; + } + append(logLine); + } + + private synchronized void append(String logLine) { + while (mLog.size() >= mMaxLines) { + mLog.remove(); + } + mLog.add(logLine); + } + + @UnsupportedAppUsage + public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + dump(pw); + } + + public synchronized void dump(PrintWriter pw) { + dump("", pw); + } + + /** + * Dumps the content of local log to print writer with each log entry predeced with indent + * + * @param indent indent that precedes each log entry + * @param pw printer writer to write into + */ + public synchronized void dump(String indent, PrintWriter pw) { + Iterator itr = mLog.iterator(); + while (itr.hasNext()) { + pw.printf("%s%s\n", indent, itr.next()); + } + } + + public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { + reverseDump(pw); + } + + public synchronized void reverseDump(PrintWriter pw) { + Iterator itr = mLog.descendingIterator(); + while (itr.hasNext()) { + pw.println(itr.next()); + } + } + + // @VisibleForTesting(otherwise = VisibleForTesting.NONE) + public synchronized void clear() { + mLog.clear(); + } + + public static class ReadOnlyLocalLog { + private final LocalLog mLog; + ReadOnlyLocalLog(LocalLog log) { + mLog = log; + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mLog.dump(pw); + } + public void dump(PrintWriter pw) { + mLog.dump(pw); + } + public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { + mLog.reverseDump(pw); + } + public void reverseDump(PrintWriter pw) { + mLog.reverseDump(pw); + } + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public ReadOnlyLocalLog readOnlyLocalLog() { + return new ReadOnlyLocalLog(this); + } +} \ No newline at end of file diff --git a/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java b/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java new file mode 100644 index 0000000000..7db62f8e9f --- /dev/null +++ b/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.internal.util; + +import android.app.AlarmManager; +import android.content.Context; +import android.os.Handler; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + + /** + * An AlarmListener that sends the specified message to a Handler and keeps the system awake until + * the message is processed. + * + * This is useful when using the AlarmManager direct callback interface to wake up the system and + * request that an object whose API consists of messages (such as a StateMachine) perform some + * action. + * + * In this situation, using AlarmManager.onAlarmListener by itself will wake up the system to send + * the message, but does not guarantee that the system will be awake until the target object has + * processed it. This is because as soon as the onAlarmListener sends the message and returns, the + * AlarmManager releases its wakelock and the system is free to go to sleep again. + */ +// TODO: b/374174952 This is an exact copy of +// frameworks/base/core/java/com/android/internal/util/WakeupMessage.java. +// This file is only used in "service-connectivity-b-platform" before the VCN modularization flag +// is fully ramped. When the flag is fully ramped and the development is finalized, this file can +// be removed. +public class WakeupMessage implements AlarmManager.OnAlarmListener { + private final AlarmManager mAlarmManager; + + @VisibleForTesting + protected final Handler mHandler; + @VisibleForTesting + protected final String mCmdName; + @VisibleForTesting + protected final int mCmd, mArg1, mArg2; + @VisibleForTesting + protected final Object mObj; + private final Runnable mRunnable; + private boolean mScheduled; + + public WakeupMessage(Context context, Handler handler, + String cmdName, int cmd, int arg1, int arg2, Object obj) { + mAlarmManager = getAlarmManager(context); + mHandler = handler; + mCmdName = cmdName; + mCmd = cmd; + mArg1 = arg1; + mArg2 = arg2; + mObj = obj; + mRunnable = null; + } + + public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) { + this(context, handler, cmdName, cmd, arg1, 0, null); + } + + public WakeupMessage(Context context, Handler handler, + String cmdName, int cmd, int arg1, int arg2) { + this(context, handler, cmdName, cmd, arg1, arg2, null); + } + + public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) { + this(context, handler, cmdName, cmd, 0, 0, null); + } + + public WakeupMessage(Context context, Handler handler, String cmdName, Runnable runnable) { + mAlarmManager = getAlarmManager(context); + mHandler = handler; + mCmdName = cmdName; + mCmd = 0; + mArg1 = 0; + mArg2 = 0; + mObj = null; + mRunnable = runnable; + } + + private static AlarmManager getAlarmManager(Context context) { + return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + } + + /** + * Schedule the message to be delivered at the time in milliseconds of the + * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup + * the device when it goes off. If schedule is called multiple times without the message being + * dispatched then the alarm is rescheduled to the new time. + */ + public synchronized void schedule(long when) { + mAlarmManager.setExact( + AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler); + mScheduled = true; + } + + /** + * Cancel all pending messages. This includes alarms that may have been fired, but have not been + * run on the handler yet. + */ + public synchronized void cancel() { + if (mScheduled) { + mAlarmManager.cancel(this); + mScheduled = false; + } + } + + @Override + public void onAlarm() { + // Once this method is called the alarm has already been fired and removed from + // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now + // be marked as unscheduled so that it can be rescheduled in the message handler. + final boolean stillScheduled; + synchronized (this) { + stillScheduled = mScheduled; + mScheduled = false; + } + if (stillScheduled) { + Message msg; + if (mRunnable == null) { + msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj); + } else { + msg = Message.obtain(mHandler, mRunnable); + } + mHandler.dispatchMessage(msg); + msg.recycle(); + } + } +} \ No newline at end of file diff --git a/Vcn/service-b/service-vcn-platform-jarjar-rules.txt b/Vcn/service-b/service-vcn-platform-jarjar-rules.txt index 36307277b4..6ec39d9532 100644 --- a/Vcn/service-b/service-vcn-platform-jarjar-rules.txt +++ b/Vcn/service-b/service-vcn-platform-jarjar-rules.txt @@ -1,5 +1,2 @@ -rule android.util.IndentingPrintWriter android.net.vcn.module.repackaged.android.util.IndentingPrintWriter rule android.util.LocalLog android.net.vcn.module.repackaged.android.util.LocalLog -rule com.android.internal.util.IndentingPrintWriter android.net.vcn.module.repackaged.com.android.internal.util.IndentingPrintWriter -rule com.android.internal.util.MessageUtils android.net.vcn.module.repackaged.com.android.internal.util.MessageUtils rule com.android.internal.util.WakeupMessage android.net.vcn.module.repackaged.com.android.internal.util.WakeupMessage \ No newline at end of file From 8f31a73b84fd96a9b2c0fa2a220cdfe65f3728fa Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 3 Jan 2025 16:21:15 -0800 Subject: [PATCH 0502/1057] Increase the timeout to deflake the VCN test This patch is to deflake testEnterSafeModeImmediately_safeModeEnabled. Previously this test required that within 0.5 seconds after setVcnConfig was called, VCN should send a VCN_STATUS_CODE_ACTIVE callback to the cts. However, sending this callback requires cts to gain carrier privileges and in some devices it takes longer than 0.5 seconds. This patch mitigates the test issue by extending the timeout. Bug: 386884143 Test: CtsVcnTestCases Flag: EXEMPT; test code Change-Id: Id5f7b70a0c7f68e58ab045be2126194f936ebb0f --- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 81630ffe6d..da6ae98d1d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -110,7 +110,7 @@ import java.util.concurrent.TimeUnit; public class VcnManagerTest extends VcnTestBase { private static final String TAG = VcnManagerTest.class.getSimpleName(); - private static final int TIMEOUT_MS = 500; + private static final int CALLBACK_TIMEOUT_MS = 5000; private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35); private static final int ACTIVE_SUB_ID_TIMEOUT_SECONDS = 60; @@ -263,7 +263,7 @@ public class VcnManagerTest extends VcnTestBase { } public void awaitOnPolicyChanged() throws Exception { - mFutureOnPolicyChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + mFutureOnPolicyChanged.get(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); } } @@ -523,14 +523,16 @@ public class VcnManagerTest extends VcnTestBase { } public int awaitOnStatusChanged() throws Exception { - final Integer status = mOnStatusChangedHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); + final Integer status = + mOnStatusChangedHistory.poll(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); // Null means timeout return status == null ? VCN_STATUS_CODE_AWAIT_TIMEOUT : status; } public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception { - return mOnGatewayConnectionErrorHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); + return mOnGatewayConnectionErrorHistory.poll( + CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); } } From 22d87e4cde6c4eb5912b8b2a648b93f0fee05308 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 3 Jan 2025 16:21:15 -0800 Subject: [PATCH 0503/1057] Increase the timeout to deflake the VCN test This patch is to deflake testEnterSafeModeImmediately_safeModeEnabled. Previously this test required that within 0.5 seconds after setVcnConfig was called, VCN should send a VCN_STATUS_CODE_ACTIVE callback to the cts. However, sending this callback requires cts to gain carrier privileges and in some devices it takes longer than 0.5 seconds. This patch mitigates the test issue by extending the timeout. Bug: 386884143 Test: CtsVcnTestCases Flag: EXEMPT; test code Change-Id: Id5f7b70a0c7f68e58ab045be2126194f936ebb0f (cherry picked from commit 8f31a73b84fd96a9b2c0fa2a220cdfe65f3728fa) --- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index 81630ffe6d..da6ae98d1d 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -110,7 +110,7 @@ import java.util.concurrent.TimeUnit; public class VcnManagerTest extends VcnTestBase { private static final String TAG = VcnManagerTest.class.getSimpleName(); - private static final int TIMEOUT_MS = 500; + private static final int CALLBACK_TIMEOUT_MS = 5000; private static final long SAFEMODE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(35); private static final int ACTIVE_SUB_ID_TIMEOUT_SECONDS = 60; @@ -263,7 +263,7 @@ public class VcnManagerTest extends VcnTestBase { } public void awaitOnPolicyChanged() throws Exception { - mFutureOnPolicyChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + mFutureOnPolicyChanged.get(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); } } @@ -523,14 +523,16 @@ public class VcnManagerTest extends VcnTestBase { } public int awaitOnStatusChanged() throws Exception { - final Integer status = mOnStatusChangedHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); + final Integer status = + mOnStatusChangedHistory.poll(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); // Null means timeout return status == null ? VCN_STATUS_CODE_AWAIT_TIMEOUT : status; } public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception { - return mOnGatewayConnectionErrorHistory.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); + return mOnGatewayConnectionErrorHistory.poll( + CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); } } From ce63e16ca85fd24fba7be148b13e2da04f4eddd1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 9 Jan 2025 11:11:56 -0800 Subject: [PATCH 0504/1057] Update VcnNetworkProvider to use thread safe Sets This patch is to fix a race condition when two threads access VcnNetworkProvider.mRequests at the same time. The issue happened when the VCN thread is removing elements and the binder thread is iterating the Set. It causes the binder thread to end up with a Null element and throw NPE This patch fixes this threading issue by changing the Set to be a thread-safe Set Bug: 382106220 Test: atest CtsVcnTestCases && atest FrameworksVcnTests Test: Set up test environment to make the race condition 90% reproducible; verified the fix by running the test for 100 times on forrest Flag: EXEMPT; low risk and small scope bug fix Change-Id: Id7598a861368454efcd0aa49721c54e11aaebdf1 --- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 2 ++ .../src/com/android/server/vcn/VcnNetworkProvider.java | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 369ef6ae6a..97f86b1bff 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -209,6 +209,8 @@ public class Vcn extends Handler { this(vcnContext, subscriptionGroup, config, snapshot, vcnCallback, new Dependencies()); } + // WARNING: This constructor executes on the binder thread. Thread safety MUST be ensured when + // accessing data within this constructor and any methods called from here. @VisibleForTesting(visibility = Visibility.PRIVATE) public Vcn( @NonNull VcnContext vcnContext, diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 99c848f53c..38fcf09145 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -36,7 +36,6 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.os.Build; import android.os.Handler; import android.os.Looper; -import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -46,6 +45,7 @@ import com.android.modules.utils.HandlerExecutor; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; /** @@ -56,12 +56,14 @@ import java.util.concurrent.Executor; * * @hide */ +// TODO(b/388919146): Implement a more generic solution to prevent concurrent modifications on +// mListeners and mRequests // TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) public class VcnNetworkProvider extends NetworkProvider { private static final String TAG = VcnNetworkProvider.class.getSimpleName(); - private final Set mListeners = new ArraySet<>(); + private final Set mListeners = ConcurrentHashMap.newKeySet(); private final Context mContext; private final Handler mHandler; @@ -72,7 +74,7 @@ public class VcnNetworkProvider extends NetworkProvider { * *

    NetworkRequests are immutable once created, and therefore can be used as stable keys. */ - private final Set mRequests = new ArraySet<>(); + private final Set mRequests = ConcurrentHashMap.newKeySet(); public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { this(context, looper, new Dependencies()); From 08d7eed3d5a20894e9c265518a352051e59ef7e2 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 13 Jan 2025 16:41:56 -0800 Subject: [PATCH 0505/1057] Unregister DeviceIdle Receiver in IpSecPacketLossDetector Ensure that when the IpSecPacketLossDetector cleans up due to the underlying network changing, that the broadcast receiver it's listening to is cleaned up. Previously this would leak broadcast receivers. Based on inspection, all instances that touch the BroadcastReceiver are done on the same looper, so we shouldn't need to guard the creation and destruction of the receiver. Also, stop closing the monitored IpSecTransform. The monitor should not have been closing the transform in the first place. Most of the time it isn't an issue; however, in the event of MOBIKE, the transform will remain open, so this is a functional bug. Bug: 389208101 Test: atest IpSecPacketLossDetectorTest:testClose Flag: EXEMPT bugfix Change-Id: I26245960c36eaa0557d377b1672cc76ab0f70b03 --- .../IpSecPacketLossDetector.java | 31 ++++++++++++------- .../routeselection/NetworkMetricMonitor.java | 2 +- .../IpSecPacketLossDetectorTest.java | 6 +++- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 6467af4355..c8c645f127 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -138,6 +138,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { @NonNull private final Object mCancellationToken = new Object(); @NonNull private final PacketLossCalculator mPacketLossCalculator; + @Nullable private BroadcastReceiver mDeviceIdleReceiver; + @Nullable private IpSecTransformWrapper mInboundTransform; @Nullable private IpSecTransformState mLastIpSecTransformState; @@ -168,19 +170,21 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // Register for system broadcasts to monitor idle mode change final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + + mDeviceIdleReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals( + intent.getAction()) + && mPowerManager.isDeviceIdleMode()) { + mLastIpSecTransformState = null; + } + } + }; getVcnContext() .getContext() .registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals( - intent.getAction()) - && mPowerManager.isDeviceIdleMode()) { - mLastIpSecTransformState = null; - } - } - }, + mDeviceIdleReceiver, intentFilter, null /* broadcastPermission not required */, mHandler); @@ -338,7 +342,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { super.close(); if (mInboundTransform != null) { - mInboundTransform.close(); + mInboundTransform = null; + } + + if (mDeviceIdleReceiver != null) { + getVcnContext().getContext().unregisterReceiver(mDeviceIdleReceiver); + mDeviceIdleReceiver = null; } } diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 14853440a1..55829a5fe9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -165,7 +165,7 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { } } - /** Set the IpSecTransform that applied to the Network being monitored */ + /** Set the IpSecTransform that is applied to the Network being monitored */ public void setInboundTransform(@NonNull IpSecTransform inTransform) { setInboundTransformInternal(new IpSecTransformWrapper(inTransform)); } diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 5db02e376f..7b1e4cc62d 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; 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.when; @@ -284,8 +285,11 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Stop the monitor mIpSecPacketLossDetector.close(); + mIpSecPacketLossDetector.close(); verifyStopped(); - verify(mIpSecTransform).close(); + + verify(mIpSecTransform, never()).close(); + verify(mContext).unregisterReceiver(any()); } @Test From 3f24d36a3ff319dc61260e126c62ea15c360a17f Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 14 Jan 2025 13:35:43 -0800 Subject: [PATCH 0506/1057] Remove Unused 'times' Import Remove an unused import due to changes in code review. Bug: 8675309 Test: compilation Flag: exempt Trivial cleanup Change-Id: I69b580de6725cad29af6dd17bc10deccf95cdda4 --- .../server/vcn/routeselection/IpSecPacketLossDetectorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index 7b1e4cc62d..c11b6bb343 100644 --- a/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/Vcn/tests/unit/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -38,7 +38,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; 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.when; From d61bd7860231f1bcc37fdb55032c1f5d9f53bd7c Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 22 Jan 2025 01:25:52 +0000 Subject: [PATCH 0507/1057] Jarjar IndentingPrintWriter with android.net.connectivity prefix This patch is to fix NoSuchMethodError thrown from VCN dumpsys when VCN is in the Tethering mainline module. Because VCN is in Tethering module, the VCN service will use a jarjared IndentingPrintWriter. During dumpsys, VcnManagementService#dump will create a IndentingPrintWriter and pass it to VcnUnderlyingNetworkTemplate#dump. Then because VcnUnderlyingNetworkTemplate fails to recognize the jarjared class, it will throw NoSuchMethodError. This patch fixes this issue by also jarjaring the IndentingPrintWriter in VCN framework library. It is aligned with the end state where all classes in the VCN framework code except APIs will be jarjared to have a android.net.connectivity prefix Bug: 390490391 Bug: 386225194 Test: atest CtsVcnTestCases(new tests) Flag: EXEMPT; low risk and small scope bug fix Change-Id: I34be6dbf816c752f6ba0b77dc4ad98c8ad71e743 --- Vcn/framework-b/framework-vcn-jarjar-rules.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Vcn/framework-b/framework-vcn-jarjar-rules.txt b/Vcn/framework-b/framework-vcn-jarjar-rules.txt index 7e27b24f74..33287b7f34 100644 --- a/Vcn/framework-b/framework-vcn-jarjar-rules.txt +++ b/Vcn/framework-b/framework-vcn-jarjar-rules.txt @@ -1,2 +1,3 @@ rule android.net.vcn.persistablebundleutils.** android.net.connectivity.android.net.vcn.persistablebundleutils.@1 -rule android.net.vcn.util.** android.net.connectivity.android.net.vcn.util.@1 \ No newline at end of file +rule android.net.vcn.util.** android.net.connectivity.android.net.vcn.util.@1 +rule android.util.IndentingPrintWriter android.net.connectivity.android.util.IndentingPrintWriter \ No newline at end of file From ee21eb02bca0b2e0a094c29e1a414048429314b7 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 21 Jan 2025 18:13:44 -0800 Subject: [PATCH 0508/1057] Verify VCN dumpsys Verify that VCN dumpsys will not crash the system. This patch prevents dumpsys issues that caused by VCN service and framework code having mismatched classes Bug: 390490391 Bug: 386225194 Test: VcnManagerTest#testSetVcnConfigOnTestNetworkAndDumpsys Flag: EXEMPT; test code Change-Id: I5a61ffaf6ee6eb4275e43085a5c10ae037b90551 --- .../android/net/vcn/cts/VcnManagerTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index da6ae98d1d..d0755fa2a8 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -757,6 +757,24 @@ public class VcnManagerTest extends VcnTestBase { } } + @Test + public void testSetVcnConfigOnTestNetworkAndDumpsys() throws Exception { + final int subId = verifyAndGetValidDataSubId(); + + try (TestNetworkWrapper testNetworkWrapper = + createTestNetworkWrapper(true /* isMetered */, subId, LOCAL_ADDRESS)) { + verifyUnderlyingCellAndRunTest(subId, (subGrp, cellNetwork, cellNetworkCb) -> { + final VcnSetupResult vcnSetupResult = + setupAndGetVcnNetwork(subGrp, cellNetwork, cellNetworkCb, testNetworkWrapper); + + runShellCommand("dumpsys vcn_management"); + + clearVcnConfigsAndVerifyNetworkTeardown( + subGrp, cellNetworkCb, vcnSetupResult.vcnNetwork); + }); + } + } + @Test public void testSetVcnConfigOnTestNetworkAndHandleDataStall() throws Exception { final int subId = verifyAndGetValidDataSubId(); From 4eb48fe868b4305633ac9d54767b6bc166cf03c7 Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Mon, 27 Jan 2025 13:37:36 +0100 Subject: [PATCH 0509/1057] Set TargetApi to BAKLAVA Generated with `cd frameworks/base/packages/Vcn/service-b && \ fdfind -t file . -x sed -i -z 's#// TODO(b\/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization\n@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)#@TargetApi(Build.VERSION_CODES.BAKLAVA)#g' Flag: EXEMPT Baklava Finalization Test: lunch mainline_modules_x86_64-next-eng && m Bug: 376680864 Bug: 374174952 Bug: 392570119 Change-Id: I1dc2af23ac85d1c90b1419a14ca992e68106e9f7 --- .../com/android/server/ConnectivityServiceInitializerB.java | 3 +-- Vcn/service-b/src/com/android/server/VcnManagementService.java | 3 +-- .../com/android/server/vcn/TelephonySubscriptionTracker.java | 3 +-- Vcn/service-b/src/com/android/server/vcn/Vcn.java | 3 +-- .../src/com/android/server/vcn/VcnGatewayConnection.java | 3 +-- .../src/com/android/server/vcn/VcnNetworkProvider.java | 3 +-- .../server/vcn/routeselection/IpSecPacketLossDetector.java | 3 +-- .../server/vcn/routeselection/NetworkMetricMonitor.java | 3 +-- .../server/vcn/routeselection/NetworkPriorityClassifier.java | 3 +-- .../server/vcn/routeselection/UnderlyingNetworkController.java | 3 +-- .../server/vcn/routeselection/UnderlyingNetworkEvaluator.java | 3 +-- 11 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java index 81c7edf4ad..b9dcc6160d 100644 --- a/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java +++ b/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java @@ -32,8 +32,7 @@ import com.android.tools.r8.keepanno.annotations.UsedByReflection; // Without this annotation, this class will be treated as unused class and be removed during build // time. @UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS) -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public final class ConnectivityServiceInitializerB extends SystemService { private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName(); private final VcnManagementService mVcnManagementService; diff --git a/Vcn/service-b/src/com/android/server/VcnManagementService.java b/Vcn/service-b/src/com/android/server/VcnManagementService.java index c9a99d729e..8edd63dc34 100644 --- a/Vcn/service-b/src/com/android/server/VcnManagementService.java +++ b/Vcn/service-b/src/com/android/server/VcnManagementService.java @@ -165,8 +165,7 @@ import java.util.concurrent.TimeUnit; * @hide */ // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN"; diff --git a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java index b04e25dff2..cedb2d1680 100644 --- a/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/Vcn/service-b/src/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -79,8 +79,7 @@ import java.util.Set; * * @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private static final String TAG = TelephonySubscriptionTracker.class.getSimpleName(); private static final boolean LOG_DBG = false; // STOPSHIP if true diff --git a/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/Vcn/service-b/src/com/android/server/vcn/Vcn.java index 97f86b1bff..0f8b2885cf 100644 --- a/Vcn/service-b/src/com/android/server/vcn/Vcn.java +++ b/Vcn/service-b/src/com/android/server/vcn/Vcn.java @@ -77,8 +77,7 @@ import java.util.Set; * * @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class Vcn extends Handler { private static final String TAG = Vcn.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java index 300b80f942..da411174f9 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnGatewayConnection.java @@ -174,8 +174,7 @@ import java.util.function.Consumer; * * @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java index 38fcf09145..bc815eb274 100644 --- a/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java +++ b/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java @@ -58,8 +58,7 @@ import java.util.concurrent.Executor; */ // TODO(b/388919146): Implement a more generic solution to prevent concurrent modifications on // mListeners and mRequests -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class VcnNetworkProvider extends NetworkProvider { private static final String TAG = VcnNetworkProvider.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index c8c645f127..aff7068b6c 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -61,8 +61,7 @@ import java.util.concurrent.TimeUnit; * *

    This class is flag gated by "network_metric_monitor" and "ipsec_tramsform_state" */ -// TODO(b/374174952) Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index 55829a5fe9..fc9c7ac8a3 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -44,8 +44,7 @@ import java.util.concurrent.Executor; * *

    This class is flag gated by "network_metric_monitor" */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public abstract class NetworkMetricMonitor implements AutoCloseable { private static final String TAG = NetworkMetricMonitor.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 705141f3f1..7cb3257193 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -52,8 +52,7 @@ import java.util.Map; import java.util.Set; /** @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) class NetworkPriorityClassifier { @NonNull private static final String TAG = NetworkPriorityClassifier.class.getSimpleName(); /** diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index bc552e7e6a..37ec0e8f40 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -75,8 +75,7 @@ import java.util.TreeSet; * * @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class UnderlyingNetworkController { @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName(); diff --git a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 776931bad7..164b59f6f0 100644 --- a/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/Vcn/service-b/src/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -52,8 +52,7 @@ import java.util.concurrent.TimeUnit; * * @hide */ -// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization -@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@TargetApi(Build.VERSION_CODES.BAKLAVA) public class UnderlyingNetworkEvaluator { private static final String TAG = UnderlyingNetworkEvaluator.class.getSimpleName(); From 43de5b945c581d864cb52e8538ec0c1f17d31fe9 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 28 Jan 2025 14:52:39 -0800 Subject: [PATCH 0510/1057] Add CTS for getConfiguredSubscriptionGroups and getMaxMtu Bug: 392954081 Test: atest CtsVcnTestCases Flag: EXEMPT; test code Change-Id: I6a7acb3556ee329883811b22b71af87f86f8013b --- .../vcn/cts/VcnGatewayConnectionConfigTest.java | 1 + .../src/android/net/vcn/cts/VcnManagerTest.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 618c3de743..203d9c0df4 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -92,6 +92,7 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { UNDERLYING_NETWORK_TEMPLATES, gatewayConnConfig.getVcnUnderlyingNetworkPriorities()); assertArrayEquals(RETRY_INTERNAL_MILLIS, gatewayConnConfig.getRetryIntervalsMillis()); + assertEquals(MAX_MTU, gatewayConnConfig.getMaxMtu()); } @Test diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java index d0755fa2a8..5aa6958f74 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnManagerTest.java @@ -95,6 +95,7 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -230,6 +231,7 @@ public class VcnManagerTest extends VcnTestBase { CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + mVcnManager.clearVcnConfig(subGrp); }); }); @@ -252,6 +254,19 @@ public class VcnManagerTest extends VcnTestBase { }); } + @Test + public void testGetConfiguredSubscriptionGroups() throws Exception { + final int dataSubId = verifyAndGetValidDataSubId(); + CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> { + SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> { + mVcnManager.setVcnConfig(subGrp, buildVcnConfig()); + assertEquals(Arrays.asList(subGrp), mVcnManager.getConfiguredSubscriptionGroups()); + + mVcnManager.clearVcnConfig(subGrp); + }); + }); + } + /** Test implementation of VcnNetworkPolicyChangeListener for verification purposes. */ private static class TestVcnNetworkPolicyChangeListener implements VcnManager.VcnNetworkPolicyChangeListener { From 7143d57186900de1b2ec9187ffd6a3215cf0fb68 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 14 Nov 2024 05:51:51 -0800 Subject: [PATCH 0511/1057] Update VCN CTS to allow unset nat timeout With aosp/3291654, VCN now allows carrier apps to unset the NAT timeout. Bug: 376339506 Bug: 391776593 Test: CtsVcnTestCases Flag: EXEMPT test code Change-Id: I703c81ad54186b53c36a9a02863233f96651e22a Merged-In: I703c81ad54186b53c36a9a02863233f96651e22a --- .../android/net/vcn/cts/VcnGatewayConnectionConfigTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java index 99d0c2ef47..518909505a 100644 --- a/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java +++ b/Vcn/tests/cts/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java @@ -178,12 +178,6 @@ public class VcnGatewayConnectionConfigTest extends VcnTestBase { @Test public void testBuilderSetMinUdpPort4500NatTimeout_invalidValues() { - try { - buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(-1); - fail("Expected exception due to invalid timeout range"); - } catch (IllegalArgumentException e) { - } - try { buildVcnGatewayConnectionConfigBase().setMinUdpPort4500NatTimeoutSeconds(119); fail("Expected exception due to invalid timeout range"); From 0bd95f840d68b8576c16c968696fe243a752705e Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 10 Feb 2025 14:43:57 -0800 Subject: [PATCH 0512/1057] Add VCN CTS to mts-tethering This patch adds CtsVcnTests to tethering MTS. Consequently, these tests will be monthly updated and installed with Tethering module on all Android R/R+ devices. Thus the patch also adds SDK checks to make sure the mainline updated tests will be skipped if SDK <= Android V, to avoid compatability issues. Bug: 376896491 Test: lunch mainline_modules_arm64-mainline-userdebug && m mts && mts-tradefed run mts-tethering; Verified on V and B Flag: EXEMPT; test code change Change-Id: Ib6d3d698925feef472d472be6def080580aa6ec3 --- Vcn/tests/cts/Android.bp | 5 +++++ Vcn/tests/cts/AndroidManifest.xml | 3 +++ Vcn/tests/cts/AndroidTest.xml | 7 +++++++ .../ConnectivityFrameworkInitializerBaklavaTest.java | 9 +++++++-- .../vcn/cts/VcnCellUnderlyingNetworkTemplateTest.java | 9 +++++++++ .../cts/src/android/net/vcn/cts/VcnConfigTest.java | 10 ++++++++-- .../net/vcn/cts/VcnGatewayConnectionConfigTest.java | 9 +++++++-- .../cts/src/android/net/vcn/cts/VcnManagerTest.java | 9 +++++++-- .../android/net/vcn/cts/VcnSystemRequirementsTest.java | 10 ++++++++-- .../src/android/net/vcn/cts/VcnTransportInfoTest.java | 9 +++++++-- .../vcn/cts/VcnWifiUnderlyingNetworkTemplateTest.java | 9 +++++++++ 11 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Vcn/tests/cts/Android.bp b/Vcn/tests/cts/Android.bp index 1756c5997a..2e2d10dcb2 100644 --- a/Vcn/tests/cts/Android.bp +++ b/Vcn/tests/cts/Android.bp @@ -24,6 +24,9 @@ android_test { "framework-connectivity-test-defaults", ], + // TODO: b/374174952 Use 36 after Android B finalization + min_sdk_version: "35", + // Include both the 32 and 64 bit versions compile_multilib: "both", @@ -57,6 +60,8 @@ android_test { test_suites: [ "cts", "general-tests", + "mts-tethering", + "mcts-tethering", ], data: [":ConnectivityTestPreparer"], host_required: ["net-tests-utils-host-common"], diff --git a/Vcn/tests/cts/AndroidManifest.xml b/Vcn/tests/cts/AndroidManifest.xml index b37e174e8a..ffcbcaa2d2 100644 --- a/Vcn/tests/cts/AndroidManifest.xml +++ b/Vcn/tests/cts/AndroidManifest.xml @@ -19,6 +19,9 @@ package="android.net.vcn.cts" android:targetSandboxVersion="2"> + + + diff --git a/Vcn/tests/cts/AndroidTest.xml b/Vcn/tests/cts/AndroidTest.xml index 0d3f529c0b..0375b9ca04 100644 --- a/Vcn/tests/cts/AndroidTest.xml +++ b/Vcn/tests/cts/AndroidTest.xml @@ -24,6 +24,13 @@