diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-07-15 02:04:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-07-15 02:04:28 +0000 |
commit | 2ce8a3b5559e2a42fc7a1781a31e47907f5511c0 (patch) | |
tree | 6898c5db5b09380dc5609b4b5f10b60416224eb7 | |
parent | 6e49820609b28b111f6489f15bf77c541999181f (diff) | |
parent | 98d8f7698e936d1a09ebcfa21d0f22b9cae5aa1e (diff) | |
download | net-android12-mainline-captiveportallogin-release.tar.gz |
Snap for 7550930 from 98d8f7698e936d1a09ebcfa21d0f22b9cae5aa1e to mainline-captiveportallogin-releaseandroid-mainline-12.0.0_r6android-mainline-12.0.0_r23android12-mainline-captiveportallogin-release
Change-Id: I46531c2664219b22733544f994ee1cf0e6a2e711
27 files changed, 1166 insertions, 955 deletions
diff --git a/client-libs/Android.bp b/client-libs/Android.bp index 9cedd29f..8c79d2a1 100644 --- a/client-libs/Android.bp +++ b/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", diff --git a/client-libs/tests/unit/Android.bp b/client-libs/tests/unit/Android.bp index 2cd39bdc..220a6c19 100644 --- a/client-libs/tests/unit/Android.bp +++ b/client-libs/tests/unit/Android.bp @@ -23,7 +23,8 @@ android_library { // Visible for Tethering and NetworkStack integration test and link NetdStaticLibTestsLib // there, so that the tests under client-libs can also be run when running tethering and // NetworkStack MTS. - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } diff --git a/client-libs/tests/unit/lint-baseline.xml b/client-libs/tests/unit/lint-baseline.xml deleted file mode 100644 index 713e3003..00000000 --- a/client-libs/tests/unit/lint-baseline.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" CollectionUtils.all(Arrays.asList(expectedFinalFlags)," - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java" - line="79" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" && CollectionUtils.all(Arrays.asList(config.flags)," - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java" - line="81" - column="44"/> - </issue> - -</issues> diff --git a/common/Android.bp b/common/Android.bp index 74aafd30..1371c8cc 100644 --- a/common/Android.bp +++ b/common/Android.bp @@ -34,9 +34,9 @@ package { java_library { name: "net-utils-device-common", srcs: [ - "device/**/*.java", + "device/com/android/net/module/util/**/*.java", // This library is used by system modules, for which the system health impact of Kotlin - // has not yet been evaluated. + // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", ":framework-annotations", ], @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -84,7 +83,11 @@ filegroup { name: "net-utils-framework-common-srcs", srcs: ["framework/**/*.java"], path: "framework", - visibility: ["//frameworks/base"], + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + "//frameworks/base/packages/Connectivity/framework", + ], } java_library { @@ -114,13 +117,15 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", - ] + ], } - filegroup { name: "net-utils-services-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], visibility: [ "//frameworks/base/services/net", @@ -135,6 +140,9 @@ java_library { ], sdk_version: "system_current", min_sdk_version: "30", + static_libs: [ + "modules-utils-build_system", + ], visibility: [ "//frameworks/base/services/net", ], @@ -147,6 +155,9 @@ filegroup { srcs: [ // Any class here *must* have a corresponding jarjar rule in the telephony build rules. "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], path: "device", visibility: [ @@ -175,6 +186,9 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ diff --git a/common/device/android/net/NetworkFactory.java b/common/device/android/net/NetworkFactory.java index bcc60897..87f6dee6 100644 --- a/common/device/android/net/NetworkFactory.java +++ b/common/device/android/net/NetworkFactory.java @@ -16,9 +16,11 @@ package android.net; +import static com.android.modules.utils.build.SdkLevel.isAtLeastS; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; -import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; @@ -27,8 +29,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.LinkedHashMap; -import java.util.Map; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -43,211 +43,72 @@ import java.util.Map; * functions can be overridden. If the bearer needs more interaction, it can * override addNetworkRequest and removeNetworkRequest which will give it each * request that passes their current filters. + * + * This class is mostly a shim which delegates to one of two implementations depending + * on the SDK level of the device it's running on. + * * @hide **/ -public class NetworkFactory extends Handler { - private static final boolean DBG = true; - private static final boolean VDBG = false; - /** - * Pass a network request to the bearer. If the bearer believes it can - * satisfy the request it should connect to the network and create a - * NetworkAgent. Once the NetworkAgent is fully functional it will - * register itself with ConnectivityService using registerNetworkAgent. - * If the bearer cannot immediately satisfy the request (no network, - * user disabled the radio, lower-scored network) it should remember - * any NetworkRequests it may be able to satisfy in the future. It may - * disregard any that it will never be able to service, for example - * those requiring a different bearer. - * msg.obj = NetworkRequest - * msg.arg1 = score - the score of the network currently satisfying this - * request. If this bearer knows in advance it cannot - * exceed this score it should not try to connect, holding the request - * for the future. - * Note that subsequent events may give a different (lower - * or higher) score for this request, transmitted to each - * NetworkFactory through additional CMD_REQUEST_NETWORK msgs - * with the same NetworkRequest but an updated score. - * Also, network conditions may change for this bearer - * allowing for a better score in the future. - * msg.arg2 = the ID of the NetworkProvider currently responsible for the - * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. - */ - public static final int CMD_REQUEST_NETWORK = 1; - - /** - * Cancel a network request - * msg.obj = NetworkRequest - */ - public static final int CMD_CANCEL_REQUEST = 2; - - /** - * Internally used to set our best-guess score. - * msg.arg1 = new score - */ - private static final int CMD_SET_SCORE = 3; +public class NetworkFactory { + static final boolean DBG = true; + static final boolean VDBG = false; - /** - * Internally used to set our current filter for coarse bandwidth changes with - * technology changes. - * msg.obj = new filter - */ - private static final int CMD_SET_FILTER = 4; + final NetworkFactoryShim mImpl; - private final Context mContext; private final String LOG_TAG; - private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = - new LinkedHashMap<>(); - - private int mScore; - private NetworkCapabilities mCapabilityFilter; - - private int mRefCount = 0; - private NetworkProvider mProvider = null; - + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. public NetworkFactory(Looper looper, Context context, String logTag, - NetworkCapabilities filter) { - super(looper); + @Nullable final NetworkCapabilities filter) { LOG_TAG = logTag; - mContext = context; - mCapabilityFilter = filter; - } - - /* Registers this NetworkFactory with the system. May only be called once per factory. */ - public void register() { - if (mProvider != null) { - throw new IllegalStateException("A NetworkFactory must only be registered once"); + if (isAtLeastS()) { + mImpl = new NetworkFactoryImpl(this, looper, context, filter); + } else { + mImpl = new NetworkFactoryLegacyImpl(this, looper, context, filter); } - if (DBG) log("Registering NetworkFactory"); - - mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, - int servingProviderId) { - handleAddRequest(request, score, servingProviderId); - } - - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - handleRemoveRequest(request); - } - }; - - ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } - /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ - public void terminate() { - if (mProvider == null) { - throw new IllegalStateException("This NetworkFactory was never registered"); - } - if (DBG) log("Unregistering NetworkFactory"); - - ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .unregisterNetworkProvider(mProvider); - - // Remove all pending messages, since this object cannot be reused. Any message currently - // being processed will continue to run. - removeCallbacksAndMessages(null); + // TODO : these two constants and the method are only used by telephony tests. Replace it in + // the tests and remove them and the associated code. + public static final int CMD_REQUEST_NETWORK = 1; + public static final int CMD_CANCEL_REQUEST = 2; + /** Like Handler#obtainMessage */ + @VisibleForTesting + public Message obtainMessage(final int what, final int arg1, final int arg2, + final @Nullable Object obj) { + return mImpl.obtainMessage(what, arg1, arg2, obj); } - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); - break; - } - case CMD_CANCEL_REQUEST: { - handleRemoveRequest((NetworkRequest) msg.obj); - break; - } - case CMD_SET_SCORE: { - handleSetScore(msg.arg1); - break; - } - case CMD_SET_FILTER: { - handleSetFilter((NetworkCapabilities) msg.obj); - break; - } - } + // Called by BluetoothNetworkFactory + public final Looper getLooper() { + return mImpl.getLooper(); } - private static class NetworkRequestInfo { - public final NetworkRequest request; - public int score; - public boolean requested; // do we have a request outstanding, limited by score - public int providerId; - - NetworkRequestInfo(NetworkRequest request, int score, int providerId) { - this.request = request; - this.score = score; - this.requested = false; - this.providerId = providerId; - } + // Refcount for simple mode requests + private int mRefCount = 0; - @Override - public String toString() { - return "{" + request + ", score=" + score + ", requested=" + requested + "}"; - } + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + public void register() { + mImpl.register(LOG_TAG); } /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent - * currently satisfying this request. + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. */ - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n == null) { - if (DBG) { - log("got request " + request + " with score " + score - + " and providerId " + servingProviderId); - } - n = new NetworkRequestInfo(request, score, servingProviderId); - mNetworkRequests.put(n.request, n); - } else { - if (VDBG) { - log("new score " + score + " for existing request " + request - + " and providerId " + servingProviderId); - } - n.score = score; - n.providerId = servingProviderId; - } - if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - - evalRequest(n); - } - - @VisibleForTesting - protected void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n != null) { - mNetworkRequests.remove(request); - if (n.requested) releaseNetworkFor(n.request); - } - } - - private void handleSetScore(int score) { - mScore = score; - evalRequests(); + public void registerIgnoringScore() { + mImpl.registerIgnoringScore(LOG_TAG); } - private void handleSetFilter(NetworkCapabilities netCap) { - mCapabilityFilter = netCap; - evalRequests(); + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + public void terminate() { + mImpl.terminate(); } - /** @deprecated None of the implementors use the score, remove this method */ - @Deprecated - public boolean acceptRequest(NetworkRequest request, int score) { - return acceptRequest(request); + protected final void reevaluateAllRequests() { + mImpl.reevaluateAllRequests(); } /** @@ -269,75 +130,10 @@ public class NetworkFactory extends Handler { * * @return {@code true} to accept the request. */ - public boolean acceptRequest(NetworkRequest request) { + public boolean acceptRequest(@NonNull final NetworkRequest request) { return true; } - private void evalRequest(NetworkRequestInfo n) { - if (VDBG) { - log("evalRequest"); - log(" n.requests = " + n.requested); - log(" n.score = " + n.score); - log(" mScore = " + mScore); - log(" request.providerId = " + n.providerId); - log(" mProvider.id = " + mProvider.getProviderId()); - } - if (shouldNeedNetworkFor(n)) { - if (VDBG) log(" needNetworkFor"); - needNetworkFor(n.request, n.score); - n.requested = true; - } else if (shouldReleaseNetworkFor(n)) { - if (VDBG) log(" releaseNetworkFor"); - releaseNetworkFor(n.request); - n.requested = false; - } else { - if (VDBG) log(" done"); - } - } - - private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { - // If this request is already tracked, it doesn't qualify for need - return !n.requested - // If the score of this request is higher or equal to that of this factory and some - // other factory is responsible for it, then this factory should not track the request - // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProvider.getProviderId()) - // If this factory can't satisfy the capability needs of this request, then it - // should not be tracked. - && n.request.canBeSatisfiedBy(mCapabilityFilter) - // Finally if the concrete implementation of the factory rejects the request, then - // don't track it. - && acceptRequest(n.request, n.score); - } - - private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { - // Don't release a request that's not tracked. - return n.requested - // The request should be released if it can't be satisfied by this factory. That - // means either of the following conditions are met : - // - Its score is too high to be satisfied by this factory and it's not already - // assigned to the factory - // - This factory can't satisfy the capability needs of the request - // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request, n.score)); - } - - private void evalRequests() { - for (NetworkRequestInfo n : mNetworkRequests.values()) { - evalRequest(n); - } - } - - /** - * Post a command, on this NetworkFactory Handler, to re-evaluate all - * outstanding requests. Can be called from a factory implementation. - */ - protected void reevaluateAllRequests() { - post(this::evalRequests); - } - /** * Can be called by a factory to release a request as unfulfillable: the request will be * removed, and the caller will get a @@ -348,56 +144,60 @@ public class NetworkFactory extends Handler { * is able to fulfill this request! */ protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { - post(() -> { - if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - final NetworkProvider provider = mProvider; - if (provider == null) { - Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); - return; - } - provider.declareNetworkRequestUnfulfillable(r); - }); + mImpl.releaseRequestAsUnfulfillableByAnyFactory(r); } // override to do simple mode (request independent) protected void startNetwork() { } protected void stopNetwork() { } - /** @deprecated none of the implementors use the score : migrate them */ - @Deprecated - protected void needNetworkFor(NetworkRequest networkRequest, int score) { - needNetworkFor(networkRequest); - } - // override to do fancier stuff - protected void needNetworkFor(NetworkRequest networkRequest) { + protected void needNetworkFor(@NonNull final NetworkRequest networkRequest) { if (++mRefCount == 1) startNetwork(); } - protected void releaseNetworkFor(NetworkRequest networkRequest) { + protected void releaseNetworkFor(@NonNull final NetworkRequest networkRequest) { if (--mRefCount == 0) stopNetwork(); } - public void setScoreFilter(int score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. + */ + @Deprecated + public void setScoreFilter(final int score) { + mImpl.setScoreFilter(score); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + public void setScoreFilter(@NonNull final NetworkScore score) { + mImpl.setScoreFilter(score); } public void setCapabilityFilter(NetworkCapabilities netCap) { - sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + mImpl.setCapabilityFilter(netCap); } @VisibleForTesting protected int getRequestCount() { - return mNetworkRequests.size(); + return mImpl.getRequestCount(); } - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mProvider.getProviderId(); + return mImpl.getSerialNumber(); } public NetworkProvider getProvider() { - return mProvider; + return mImpl.getProvider(); } protected void log(String s) { @@ -405,18 +205,11 @@ public class NetworkFactory extends Handler { } public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println(toString()); - for (NetworkRequestInfo n : mNetworkRequests.values()) { - writer.println(" " + n); - } + mImpl.dump(fd, writer, args); } @Override public String toString() { - return "{" + LOG_TAG + " - providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size() + ", refCount=" + mRefCount - + "}"; + return "{" + LOG_TAG + " " + mImpl.toString() + "}"; } } diff --git a/common/device/android/net/NetworkFactoryImpl.java b/common/device/android/net/NetworkFactoryImpl.java new file mode 100644 index 00000000..439ea142 --- /dev/null +++ b/common/device/android/net/NetworkFactoryImpl.java @@ -0,0 +1,323 @@ +/* + * 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; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.net.NetworkProvider.NetworkOfferCallback; +import android.os.Looper; +import android.os.Message; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryLegacyImpl +class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // A score that will win against everything, so that score filtering will let all requests + // through + // TODO : remove this and replace with an API to listen to all requests. + @NonNull + private static final NetworkScore INVINCIBLE_SCORE = + new NetworkScore.Builder().setLegacyInt(1000).build(); + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + */ + // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests + // and remove them and the associated code. + private static final int CMD_REQUEST_NETWORK = NetworkFactory.CMD_REQUEST_NETWORK; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + private static final int CMD_CANCEL_REQUEST = NetworkFactory.CMD_CANCEL_REQUEST; + + /** + * Internally used to set our best-guess score. + * msg.obj = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + /** + * Internally used to send the network offer associated with this factory. + * No arguments, will read from members + */ + private static final int CMD_OFFER_NETWORK = 5; + + /** + * Internally used to send the request to listen to all requests. + * No arguments, will read from members + */ + private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; + + private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = + new LinkedHashMap<>(); + + @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); + + private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull final NetworkRequest request) { + handleAddRequest(request); + } + + @Override + public void onNetworkUnneeded(@NonNull final NetworkRequest request) { + handleRemoveRequest(request); + } + }; + @NonNull private final Executor mExecutor = command -> post(command); + + + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. + NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, + @Nullable final NetworkCapabilities filter) { + super(parent, looper, context, + null != filter ? filter : + NetworkCapabilities.Builder.withoutDefaultCapabilities().build()); + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + register(logTag, false); + } + + /** + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. + */ + @Override public void registerIgnoringScore(final String logTag) { + register(logTag, true); + } + + private void register(final String logTag, final boolean listenToAllRequests) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + + // The mScore and mCapabilityFilter members can only be accessed on the handler thread. + // TODO : offer a separate API to listen to all requests instead + if (listenToAllRequests) { + sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); + } else { + sendMessage(obtainMessage(CMD_OFFER_NETWORK)); + } + } + + private void handleOfferNetwork(@NonNull final NetworkScore score) { + mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore((NetworkScore) msg.obj); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + case CMD_OFFER_NETWORK: { + handleOfferNetwork(mScore); + break; + } + case CMD_LISTEN_TO_ALL_REQUESTS: { + handleOfferNetwork(INVINCIBLE_SCORE); + break; + } + } + } + + private static class NetworkRequestInfo { + @NonNull public final NetworkRequest request; + public boolean requested; // do we have a request outstanding, limited by score + + NetworkRequestInfo(@NonNull final NetworkRequest request) { + this.request = request; + this.requested = false; + } + + @Override + public String toString() { + return "{" + request + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + */ + private void handleAddRequest(@NonNull final NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) mParent.log("got request " + request); + n = new NetworkRequestInfo(request); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) mParent.log("handle existing request " + request); + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + if (mParent.acceptRequest(request)) { + n.requested = true; + mParent.needNetworkFor(request); + } + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(@NonNull final NetworkScore score) { + if (mScore.equals(score)) return; + mScore = score; + mParent.reevaluateAllRequests(); + } + + private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { + if (netCap.equals(mCapabilityFilter)) return; + mCapabilityFilter = netCap; + mParent.reevaluateAllRequests(); + } + + @Override public final void reevaluateAllRequests() { + if (mProvider == null) return; + mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); + } + + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. + */ + @Deprecated + public void setScoreFilter(final int score) { + setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score)); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/common/device/android/net/NetworkFactoryLegacyImpl.java b/common/device/android/net/NetworkFactoryLegacyImpl.java new file mode 100644 index 00000000..6dd0adb0 --- /dev/null +++ b/common/device/android/net/NetworkFactoryLegacyImpl.java @@ -0,0 +1,398 @@ +/* + * 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; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryImpl +class NetworkFactoryLegacyImpl extends Handler + implements NetworkFactoryShim { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. + */ + public static final int CMD_REQUEST_NETWORK = 1; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + public static final int CMD_CANCEL_REQUEST = 2; + + /** + * Internally used to set our best-guess score. + * msg.arg1 = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + final Context mContext; + final NetworkFactory mParent; + + private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = + new LinkedHashMap<>(); + + private int mScore; + NetworkCapabilities mCapabilityFilter; + + NetworkProvider mProvider = null; + + NetworkFactoryLegacyImpl(NetworkFactory parent, Looper looper, Context context, + NetworkCapabilities filter) { + super(looper); + mParent = parent; + mContext = context; + mCapabilityFilter = filter; + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryLegacyImpl.this.getLooper(), + logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request, score, servingProviderId); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + } + + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + @Override public void terminate() { + if (mProvider == null) { + throw new IllegalStateException("This NetworkFactory was never registered"); + } + if (DBG) mParent.log("Unregistering NetworkFactory"); + + ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .unregisterNetworkProvider(mProvider); + + // Remove all pending messages, since this object cannot be reused. Any message currently + // being processed will continue to run. + removeCallbacksAndMessages(null); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore(msg.arg1); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + } + } + + private static class NetworkRequestInfo { + public final NetworkRequest request; + public int score; + public boolean requested; // do we have a request outstanding, limited by score + public int providerId; + + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + this.request = request; + this.score = score; + this.requested = false; + this.providerId = providerId; + } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. + */ + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) { + mParent.log("got request " + request + " with score " + score + + " and providerId " + servingProviderId); + } + n = new NetworkRequestInfo(request, score, servingProviderId); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) { + mParent.log("new score " + score + " for existing request " + request + + " and providerId " + servingProviderId); + } + n.score = score; + n.providerId = servingProviderId; + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + evalRequest(n); + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(int score) { + mScore = score; + evalRequests(); + } + + private void handleSetFilter(NetworkCapabilities netCap) { + mCapabilityFilter = netCap; + evalRequests(); + } + + /** + * Overridable function to provide complex filtering. + * Called for every request every time a new NetworkRequest is seen + * and whenever the filterScore or filterNetworkCapabilities change. + * + * acceptRequest can be overridden to provide complex filter behavior + * for the incoming requests + * + * For output, this class will call {@link NetworkFactory#needNetworkFor} and + * {@link NetworkFactory#releaseNetworkFor} for every request that passes the filters. + * If you don't need to see every request, you can leave the base + * implementations of those two functions and instead override + * {@link NetworkFactory#startNetwork} and {@link NetworkFactory#stopNetwork}. + * + * If you want to see every score fluctuation on every request, set + * your score filter to a very high number and watch {@link NetworkFactory#needNetworkFor}. + * + * @return {@code true} to accept the request. + */ + public boolean acceptRequest(NetworkRequest request) { + return mParent.acceptRequest(request); + } + + private void evalRequest(NetworkRequestInfo n) { + if (VDBG) { + mParent.log("evalRequest"); + mParent.log(" n.requests = " + n.requested); + mParent.log(" n.score = " + n.score); + mParent.log(" mScore = " + mScore); + mParent.log(" request.providerId = " + n.providerId); + mParent.log(" mProvider.id = " + mProvider.getProviderId()); + } + if (shouldNeedNetworkFor(n)) { + if (VDBG) mParent.log(" needNetworkFor"); + mParent.needNetworkFor(n.request); + n.requested = true; + } else if (shouldReleaseNetworkFor(n)) { + if (VDBG) mParent.log(" releaseNetworkFor"); + mParent.releaseNetworkFor(n.request); + n.requested = false; + } else { + if (VDBG) mParent.log(" done"); + } + } + + private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { + // If this request is already tracked, it doesn't qualify for need + return !n.requested + // If the score of this request is higher or equal to that of this factory and some + // other factory is responsible for it, then this factory should not track the request + // because it has no hope of satisfying it. + && (n.score < mScore || n.providerId == mProvider.getProviderId()) + // If this factory can't satisfy the capability needs of this request, then it + // should not be tracked. + && n.request.canBeSatisfiedBy(mCapabilityFilter) + // Finally if the concrete implementation of the factory rejects the request, then + // don't track it. + && acceptRequest(n.request); + } + + private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { + // Don't release a request that's not tracked. + return n.requested + // The request should be released if it can't be satisfied by this factory. That + // means either of the following conditions are met : + // - Its score is too high to be satisfied by this factory and it's not already + // assigned to the factory + // - This factory can't satisfy the capability needs of the request + // - The concrete implementation of the factory rejects the request + && ((n.score > mScore && n.providerId != mProvider.getProviderId()) + || !n.request.canBeSatisfiedBy(mCapabilityFilter) + || !acceptRequest(n.request)); + } + + private void evalRequests() { + for (NetworkRequestInfo n : mNetworkRequests.values()) { + evalRequest(n); + } + } + + /** + * Post a command, on this NetworkFactory Handler, to re-evaluate all + * outstanding requests. Can be called from a factory implementation. + */ + @Override public void reevaluateAllRequests() { + post(this::evalRequests); + } + + /** + * Can be called by a factory to release a request as unfulfillable: the request will be + * removed, and the caller will get a + * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function + * returns. + * + * Note: this should only be called by factory which KNOWS that it is the ONLY factory which + * is able to fulfill this request! + */ + @Override public void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { + post(() -> { + if (DBG) mParent.log("releaseRequestAsUnfulfillableByAnyFactory: " + r); + final NetworkProvider provider = mProvider; + if (provider == null) { + mParent.log("Ignoring attempt to release unregistered request as unfulfillable"); + return; + } + provider.declareNetworkRequestUnfulfillable(r); + }); + } + + @Override public void setScoreFilter(int score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + } + + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + setScoreFilter(score.getLegacyInt()); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + @Override public int getSerialNumber() { + return mProvider.getProviderId(); + } + + @Override public NetworkProvider getProvider() { + return mProvider; + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/common/device/android/net/NetworkFactoryShim.java b/common/device/android/net/NetworkFactoryShim.java new file mode 100644 index 00000000..dfbb5ec1 --- /dev/null +++ b/common/device/android/net/NetworkFactoryShim.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; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Extract an interface for multiple implementation of {@link NetworkFactory}, depending on the SDK + * version. + * + * Known implementations: + * - {@link NetworkFactoryImpl}: For Android S+ + * - {@link NetworkFactoryLegacyImpl}: For Android R- + * + * @hide + */ +interface NetworkFactoryShim { + void register(String logTag); + + default void registerIgnoringScore(String logTag) { + throw new UnsupportedOperationException(); + } + + void terminate(); + + void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r); + + void reevaluateAllRequests(); + + void setScoreFilter(int score); + + void setScoreFilter(@NonNull NetworkScore score); + + void setCapabilityFilter(NetworkCapabilities netCap); + + int getRequestCount(); + + int getSerialNumber(); + + NetworkProvider getProvider(); + + void dump(FileDescriptor fd, PrintWriter writer, String[] args); + + // All impls inherit Handler + @VisibleForTesting + Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj); + + Looper getLooper(); +} diff --git a/common/device/com/android/net/module/util/structs/NsHeader.java b/common/device/com/android/net/module/util/structs/NsHeader.java index 6e0aa508..2e8b77ba 100644 --- a/common/device/com/android/net/module/util/structs/NsHeader.java +++ b/common/device/com/android/net/module/util/structs/NsHeader.java @@ -50,8 +50,12 @@ public class NsHeader extends Struct { @Field(order = 1, type = Type.Ipv6Address) public Inet6Address target; - public NsHeader(final Inet6Address target) { - this.reserved = 0; + NsHeader(int reserved, final Inet6Address target) { + this.reserved = reserved; this.target = target; } + + public NsHeader(final Inet6Address target) { + this(0, target); + } } diff --git a/common/framework/com/android/net/module/util/CollectionUtils.java b/common/framework/com/android/net/module/util/CollectionUtils.java index 4fce8f50..0696cca8 100644 --- a/common/framework/com/android/net/module/util/CollectionUtils.java +++ b/common/framework/com/android/net/module/util/CollectionUtils.java @@ -27,6 +27,7 @@ import java.util.function.Predicate; /** * Utilities for {@link Collection} and arrays. + * @hide */ public final class CollectionUtils { private CollectionUtils() {} diff --git a/common/framework/com/android/net/module/util/ConnectivitySettingsUtils.java b/common/framework/com/android/net/module/util/ConnectivitySettingsUtils.java new file mode 100644 index 00000000..b7eb70b0 --- /dev/null +++ b/common/framework/com/android/net/module/util/ConnectivitySettingsUtils.java @@ -0,0 +1,127 @@ +/* + * 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.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; + +/** + * Collection of connectivity settings utilities. + * + * @hide + */ +public class ConnectivitySettingsUtils { + public static final int PRIVATE_DNS_MODE_OFF = 1; + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + + public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode"; + public static final String PRIVATE_DNS_MODE = "private_dns_mode"; + public static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; + public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; + public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; + public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier"; + + /** + * Get private DNS mode as string. + * + * @param mode One of the private DNS values. + * @return A string of private DNS mode. + */ + public static String getPrivateDnsModeAsString(int mode) { + switch (mode) { + case PRIVATE_DNS_MODE_OFF: + return PRIVATE_DNS_MODE_OFF_STRING; + case PRIVATE_DNS_MODE_OPPORTUNISTIC: + return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; + case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + private static int getPrivateDnsModeAsInt(String mode) { + switch (mode) { + case "off": + return PRIVATE_DNS_MODE_OFF; + case "hostname": + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + case "opportunistic": + return PRIVATE_DNS_MODE_OPPORTUNISTIC; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + /** + * Get private DNS mode from settings. + * + * @param context The Context to query the private DNS mode from settings. + * @return An integer of private DNS mode. + */ + public static int getPrivateDnsMode(@NonNull Context context) { + final ContentResolver cr = context.getContentResolver(); + String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); + if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; + return getPrivateDnsModeAsInt(mode); + } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + */ + public static void setPrivateDnsMode(@NonNull Context context, int mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, + getPrivateDnsModeAsString(mode)); + } + + /** + * Get specific private dns provider name from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The specific private dns provider name, or null if no setting value. + */ + @Nullable + public static String getPrivateDnsHostname(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); + } + + /** + * Set specific private dns provider name to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param specifier The specific private dns provider name. + */ + public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) { + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier); + } +} diff --git a/common/framework/com/android/net/module/util/ConnectivityUtils.java b/common/framework/com/android/net/module/util/ConnectivityUtils.java index 382912bf..c135e466 100644 --- a/common/framework/com/android/net/module/util/ConnectivityUtils.java +++ b/common/framework/com/android/net/module/util/ConnectivityUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; /** * Various utilities used in connectivity code. + * @hide */ public final class ConnectivityUtils { private ConnectivityUtils() {} diff --git a/common/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/common/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 4c7d675e..d4b1c9e0 100644 --- a/common/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/common/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -44,8 +44,15 @@ import com.android.internal.annotations.VisibleForTesting; /** * Utilities to examine {@link android.net.NetworkCapabilities}. + * @hide */ public final class NetworkCapabilitiesUtils { + /** + * See android.net.NetworkCapabilities.TRANSPORT_USB + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int TRANSPORT_USB = 8; + // Transports considered to classify networks in UI, in order of which transport should be // surfaced when there are multiple transports. Transports not in this list do not have // an ordering preference (in practice they will have a deterministic order based on the @@ -63,7 +70,8 @@ public final class NetworkCapabilitiesUtils { TRANSPORT_WIFI_AWARE, TRANSPORT_BLUETOOTH, TRANSPORT_WIFI, - TRANSPORT_ETHERNET + TRANSPORT_ETHERNET, + TRANSPORT_USB // Notably, TRANSPORT_TEST is not in this list as any network that has TRANSPORT_TEST and // one of the above transports should be counted as that transport, to keep tests as @@ -133,7 +141,8 @@ public final class NetworkCapabilitiesUtils { * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_OEM_PAID) + (1 << NET_CAPABILITY_ENTERPRISE) + | (1 << NET_CAPABILITY_OEM_PAID) | (1 << NET_CAPABILITY_OEM_PRIVATE); /** diff --git a/common/framework/com/android/net/module/util/NetworkIdentityUtils.java b/common/framework/com/android/net/module/util/NetworkIdentityUtils.java index 94e60178..b641753c 100644 --- a/common/framework/com/android/net/module/util/NetworkIdentityUtils.java +++ b/common/framework/com/android/net/module/util/NetworkIdentityUtils.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; /** * Utilities to examine {@link android.net.NetworkIdentity}. + * @hide */ public class NetworkIdentityUtils { /** diff --git a/common/framework/com/android/net/module/util/NetworkStackConstants.java b/common/framework/com/android/net/module/util/NetworkStackConstants.java index b7062e76..f7151d7b 100644 --- a/common/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/common/framework/com/android/net/module/util/NetworkStackConstants.java @@ -148,7 +148,10 @@ public final class NetworkStackConstants { public static final int ICMPV6_ND_OPTION_RDNSS = 25; public static final int ICMPV6_ND_OPTION_PREF64 = 38; + public static final int ICMPV6_RS_HEADER_LEN = 8; public static final int ICMPV6_RA_HEADER_LEN = 16; + public static final int ICMPV6_NS_HEADER_LEN = 24; + public static final int ICMPV6_NA_HEADER_LEN = 24; public static final int NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER = 1 << 31; public static final int NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED = 1 << 30; diff --git a/common/jarjar-rules-shared.txt b/common/jarjar-rules-shared.txt index a7fda7c0..e26999dd 100644 --- a/common/jarjar-rules-shared.txt +++ b/common/jarjar-rules-shared.txt @@ -1,2 +1,3 @@ rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 +rule com.android.modules.utils.build.** com.android.net.module.util.build.$1 diff --git a/common/lint-baseline.xml b/common/lint-baseline.xml deleted file mode 100644 index 4c54e9fc..00000000 --- a/common/lint-baseline.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> - - <issue - id="NewApi" - message="Call requires API level R (current min is 29): `android.net.NetworkRequest#canBeSatisfiedBy`" - errorLine1=" && n.request.canBeSatisfiedBy(mCapabilityFilter)" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/device/android/net/NetworkFactory.java" - line="307" - column="26"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 29): `android.net.NetworkRequest#canBeSatisfiedBy`" - errorLine1=" || !n.request.canBeSatisfiedBy(mCapabilityFilter)" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/device/android/net/NetworkFactory.java" - line="323" - column="35"/> - </issue> - -</issues> diff --git a/common/native/bpf_syscall_wrappers/Android.bp b/common/native/bpf_syscall_wrappers/Android.bp index fa906554..befb9f8f 100644 --- a/common/native/bpf_syscall_wrappers/Android.bp +++ b/common/native/bpf_syscall_wrappers/Android.bp @@ -35,5 +35,6 @@ cc_library_headers { visibility: [ "//packages/modules/Connectivity/Tethering", "//system/bpf/libbpf_android", + "//system/memory/lmkd", ], } diff --git a/common/tests/unit/Android.bp b/common/tests/unit/Android.bp index 45a89b0b..23835fe9 100644 --- a/common/tests/unit/Android.bp +++ b/common/tests/unit/Android.bp @@ -10,6 +10,7 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], min_sdk_version: "29", + defaults: ["framework-connectivity-test-defaults"], static_libs: [ "net-utils-framework-common", "androidx.test.rules", @@ -23,7 +24,8 @@ android_library { ], visibility: [ "//frameworks/base/packages/Tethering/tests/integration", - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } diff --git a/common/tests/unit/lint-baseline.xml b/common/tests/unit/lint-baseline.xml index 0990916f..e3a6c1e1 100644 --- a/common/tests/unit/lint-baseline.xml +++ b/common/tests/unit/lint-baseline.xml @@ -3,325 +3,6 @@ <issue id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertTrue(CollectionUtils.any(listOf("A", "B", "C", "D", "E")) { it == "E" })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="32" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf("A", "B", "C", "D", "E")) { it == "F" })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="33" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertTrue(CollectionUtils.any(listOf("AA", "BBB")) { it.length >= 3 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="34" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf("A", "BB", "CCC")) { it.length >= 4 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="35" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf("A", "BB", "CCC")) { it.length < 0 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="36" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf<String>()) { true })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="37" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf<String>()) { false })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="38" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertTrue(CollectionUtils.any(listOf("A")) { true })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="39" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#any`" - errorLine1=" assertFalse(CollectionUtils.any(listOf("A")) { false })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="40" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#indexOf`" - errorLine1=" assertEquals(4, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "E" })" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="45" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#indexOf`" - errorLine1=" assertEquals(0, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "A" })" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="46" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#indexOf`" - errorLine1=" assertEquals(1, CollectionUtils.indexOf(listOf("AA", "BBB", "CCCC")) { it.length >= 3 })" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="47" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#indexOf`" - errorLine1=" assertEquals(1, CollectionUtils.indexOf(listOf("AA", null, "CCCC")) { it == null })" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="48" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#indexOf`" - errorLine1=" assertEquals(1, CollectionUtils.indexOf(listOf(null, "CCCC")) { it != null })" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="49" - column="41"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="54" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "F" })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="55" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertFalse(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length > 2 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="56" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length >= 1 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="57" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length < 4 })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="58" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf<String>()) { true })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="59" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf<String>()) { false })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="60" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertTrue(CollectionUtils.all(listOf(1)) { true })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="61" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.CollectionUtils#all`" - errorLine1=" assertFalse(CollectionUtils.all(listOf(1)) { false })" - errorLine2=" ~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt" - line="62" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertTrue(isIPv6ULA(parseNumericAddress("fc00::")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="38" - column="20"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertTrue(isIPv6ULA(parseNumericAddress("fc00::1")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="39" - column="20"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertTrue(isIPv6ULA(parseNumericAddress("fc00:1234::5678")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="40" - column="20"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertTrue(isIPv6ULA(parseNumericAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="41" - column="20"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertFalse(isIPv6ULA(parseNumericAddress("fe00::")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="43" - column="21"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.ConnectivityUtils#isIPv6ULA`" - errorLine1=" assertFalse(isIPv6ULA(parseNumericAddress("2480:1248::123:456")));" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java" - line="44" - column="21"/> - </issue> - - <issue - id="NewApi" message="Call requires API level R (current min is 29): `android.app.AppOpsManager#noteOp`" errorLine1=" when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME," errorLine2=" ~~~~~~"> @@ -355,138 +36,6 @@ <issue id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_WIFI, getDisplayTransport(intArrayOf(TRANSPORT_WIFI)))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="53" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_CELLULAR, getDisplayTransport(intArrayOf(TRANSPORT_CELLULAR)))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="54" - column="42"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_BLUETOOTH, getDisplayTransport(intArrayOf(TRANSPORT_BLUETOOTH)))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="55" - column="43"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_ETHERNET, getDisplayTransport(intArrayOf(TRANSPORT_ETHERNET)))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="56" - column="42"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_WIFI_AWARE, getDisplayTransport(intArrayOf(TRANSPORT_WIFI_AWARE)))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="57" - column="44"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_VPN, getDisplayTransport(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="59" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_VPN, getDisplayTransport(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="61" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_WIFI, getDisplayTransport(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="64" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" assertEquals(TRANSPORT_ETHERNET, getDisplayTransport(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="66" - column="42"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#getDisplayTransport`" - errorLine1=" getDisplayTransport(intArrayOf())" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="70" - column="13"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#packBits`" - errorLine1=" assertEquals(packedBits, packBits(bits))" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="87" - column="34"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#unpackBits`" - errorLine1=" assertTrue(bits contentEquals unpackBits(packedBits))" - errorLine2=" ~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="88" - column="39"/> - </issue> - - <issue - id="NewApi" message="Call requires API level R (current min is 29): `android.net.NetworkCapabilities()`" errorLine1=" val nc = NetworkCapabilities()" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> @@ -496,147 +45,4 @@ column="18"/> </issue> - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#inferRestrictedCapability`" - errorLine1=" assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="95" - column="46"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#inferRestrictedCapability`" - errorLine1=" assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="99" - column="45"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#inferRestrictedCapability`" - errorLine1=" assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="104" - column="46"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkCapabilitiesUtils#inferRestrictedCapability`" - errorLine1=" assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt" - line="108" - column="45"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberId`" - errorLine1=" assertEquals("123456...", scrubSubscriberId("1234567890123"))" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="34" - column="35"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberId`" - errorLine1=" assertEquals("123456...", scrubSubscriberId("1234567"))" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="35" - column="35"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberId`" - errorLine1=" assertEquals("123...", scrubSubscriberId("123"))" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="36" - column="32"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberId`" - errorLine1=" assertEquals("...", scrubSubscriberId(""))" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="37" - column="29"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberId`" - errorLine1=" assertEquals("null", scrubSubscriberId(null))" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="38" - column="30"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberIds`" - errorLine1=" assertContainsStringsExactly(scrubSubscriberIds(arrayOf("1234567", "", null))!!," - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="43" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberIds`" - errorLine1=" assertContainsStringsExactly(scrubSubscriberIds(arrayOf("12345"))!!, "12345...")" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="45" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberIds`" - errorLine1=" assertContainsStringsExactly(scrubSubscriberIds(arrayOf())!!)" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="46" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `com.android.net.module.util.NetworkIdentityUtils#scrubSubscriberIds`" - errorLine1=" assertNull(scrubSubscriberIds(null))" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/libs/net/common/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt" - line="47" - column="20"/> - </issue> - </issues> diff --git a/common/tests/unit/src/com/android/net/module/util/StructTest.java b/common/tests/unit/src/com/android/net/module/util/StructTest.java index df74398f..eabc14b4 100644 --- a/common/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/common/tests/unit/src/com/android/net/module/util/StructTest.java @@ -31,7 +31,6 @@ import android.net.MacAddress; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.util.HexDump; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; diff --git a/common/testutils/Android.bp b/common/testutils/Android.bp index d4465dd7..d29c1cd9 100644 --- a/common/testutils/Android.bp +++ b/common/testutils/Android.bp @@ -22,7 +22,10 @@ java_library { "devicetests/**/*.java", "devicetests/**/*.kt", ], - defaults: ["lib_mockito_extended"], + defaults: [ + "framework-connectivity-test-defaults", + "lib_mockito_extended" + ], libs: [ "androidx.annotation_annotation", ], @@ -32,6 +35,7 @@ java_library { "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", + "modules-utils-build_system", ], } diff --git a/common/testutils/devicetests/com/android/testutils/TestHttpServer.kt b/common/testutils/devicetests/com/android/testutils/TestHttpServer.kt index 7aae8e3b..39ce4872 100644 --- a/common/testutils/devicetests/com/android/testutils/TestHttpServer.kt +++ b/common/testutils/devicetests/com/android/testutils/TestHttpServer.kt @@ -54,12 +54,12 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( uri: Uri, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map<String, String>? = null, content: String = "" ) { addResponse(Request(uri.path ?: "", Method.GET, uri.query ?: ""), - statusCode, locationHeader, content) + statusCode, headers, content) } /** @@ -68,11 +68,13 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( request: Request, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map<String, String>? = null, content: String = "" ) { val response = newFixedLengthResponse(statusCode, "text/plain", content) - locationHeader?.let { response.addHeader("Location", it) } + headers?.forEach { + (key, value) -> response.addHeader(key, value) + } responses[request] = response } diff --git a/common/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/common/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 5b978617..36c09ce6 100644 --- a/common/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/common/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -26,6 +26,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder +import com.android.modules.utils.build.SdkLevel.isAtLeastS import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -39,7 +40,8 @@ import java.util.concurrent.TimeUnit fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = tnm.createTunInterface(arrayOf(interfaceAddr)) + val iface = if (isAtLeastS()) tnm.createTunInterface(listOf(interfaceAddr)) + else tnm.createTunInterface(arrayOf(interfaceAddr)) return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) } @@ -51,7 +53,7 @@ fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs class TestNetworkTracker internal constructor( val context: Context, val iface: TestNetworkInterface, - tnm: TestNetworkManager, + val tnm: TestNetworkManager, setupTimeoutMs: Long ) { private val cm = context.getSystemService(ConnectivityManager::class.java) @@ -87,5 +89,6 @@ class TestNetworkTracker internal constructor( fun teardown() { cm.unregisterNetworkCallback(networkCallback) + tnm.teardownTestNetwork(network) } }
\ No newline at end of file diff --git a/common/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt b/common/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt new file mode 100644 index 00000000..21bd60c9 --- /dev/null +++ b/common/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt @@ -0,0 +1,75 @@ +/* + * 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.testutils + +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.util.Log +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.fail + +class TestableNetworkOfferCallback(val timeoutMs: Long, private val noCallbackTimeoutMs: Long) + : NetworkProvider.NetworkOfferCallback { + private val TAG = this::class.simpleName + val history = ArrayTrackRecord<CallbackEntry>().newReadHead() + + sealed class CallbackEntry { + data class OnNetworkNeeded(val request: NetworkRequest) : CallbackEntry() + data class OnNetworkUnneeded(val request: NetworkRequest) : CallbackEntry() + } + + /** + * Called by the system when a network for this offer is needed to satisfy some + * networking request. + */ + override fun onNetworkNeeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkNeeded $request") + history.add(CallbackEntry.OnNetworkNeeded(request)) + } + + /** + * Called by the system when this offer is no longer valuable for this request. + */ + override fun onNetworkUnneeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkUnneeded $request") + history.add(CallbackEntry.OnNetworkUnneeded(request)) + } + + inline fun <reified T : CallbackEntry> expectCallbackThat( + crossinline predicate: (T) -> Boolean + ) { + val event = history.poll(timeoutMs) + ?: fail("Did not receive callback after ${timeoutMs}ms") + if (event !is T || !predicate(event)) fail("Received unexpected callback $event") + } + + fun expectOnNetworkNeeded(capabilities: NetworkCapabilities) = + expectCallbackThat<CallbackEntry.OnNetworkNeeded> { + it.request.canBeSatisfiedBy(capabilities) + } + + fun expectOnNetworkUnneeded(capabilities: NetworkCapabilities) = + expectCallbackThat<CallbackEntry.OnNetworkUnneeded> { + it.request.canBeSatisfiedBy(capabilities) + } + + fun assertNoCallback() { + val cb = history.poll(noCallbackTimeoutMs) + if (null != cb) fail("Expected no callback but got $cb") + } +}
\ No newline at end of file diff --git a/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d5c3a2a0..8477151b 100644 --- a/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -23,13 +23,19 @@ import kotlin.test.assertTrue import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L +const val TOKEN_ANY = -1 open class TestableNetworkStatsProvider( val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS ) : NetworkStatsProvider() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String?, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() + data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -41,6 +47,10 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnRequestStatsUpdate(token)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + override fun onSetLimit(iface: String, quotaBytes: Long) { history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } @@ -49,8 +59,13 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnSetAlert(quotaBytes)) } - fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { - assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs): Int { + val event = history.poll(timeout) + assertTrue(event is CallbackType.OnRequestStatsUpdate) + if (token != TOKEN_ANY) { + assertEquals(token, event.token) + } + return event.token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { diff --git a/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index f15f610b..c039cad1 100644 --- a/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/common/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -32,6 +32,7 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp val uidStats: NetworkStats ) : CallbackType() object NotifyWarningOrLimitReached : CallbackType() + object LegacyNotifyLimitReached : CallbackType() object NotifyAlertReached : CallbackType() object Unregister : CallbackType() } @@ -46,6 +47,11 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp history.add(CallbackType.NotifyWarningOrLimitReached) } + override fun notifyLimitReached() { + // Older callback renamed to notifyWarningOrLimitReached in S + history.add(CallbackType.LegacyNotifyLimitReached) + } + override fun notifyAlertReached() { history.add(CallbackType.NotifyAlertReached) } @@ -72,6 +78,9 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp fun expectNotifyWarningOrLimitReached() = assertEquals(CallbackType.NotifyWarningOrLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectLegacyNotifyLimitReached() = + assertEquals(CallbackType.LegacyNotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectNotifyAlertReached() = assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) |