Add Qos Callback support
* Provide App Developers Qos related info associated to a bound socket through ConnectivityManager * Qos sessions are generated and filtered by Network Agents and sent back through the Connectivity Service to the API consumer. * The structure of the code within com.android.server is designed to support different types of filters in the the future. * The first type of Qos Attributes are related to EPS Bearers in order support RCS. Bug: 155176305 Test: Added to cts/NetworkAgentTest Test: Added to ConnectivityServiceTest Change-Id: I145dd065d9deeee449eb9695ab3f6c8556ee7c09
This commit is contained in:
@@ -167,6 +167,7 @@ import android.net.INetworkMonitor;
|
||||
import android.net.INetworkMonitorCallbacks;
|
||||
import android.net.INetworkPolicyListener;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.IQosCallback;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
import android.net.IpPrefix;
|
||||
@@ -190,6 +191,9 @@ import android.net.NetworkStackClient;
|
||||
import android.net.NetworkState;
|
||||
import android.net.NetworkTestResultParcelable;
|
||||
import android.net.ProxyInfo;
|
||||
import android.net.QosCallbackException;
|
||||
import android.net.QosFilter;
|
||||
import android.net.QosSession;
|
||||
import android.net.ResolverParamsParcel;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.RouteInfoParcel;
|
||||
@@ -218,6 +222,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -226,10 +231,12 @@ import android.security.Credentials;
|
||||
import android.security.KeyStore;
|
||||
import android.system.Os;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.data.EpsBearerQosSessionAttributes;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
@@ -251,6 +258,7 @@ import com.android.server.connectivity.Nat464Xlat;
|
||||
import com.android.server.connectivity.NetworkAgentInfo;
|
||||
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
||||
import com.android.server.connectivity.ProxyTracker;
|
||||
import com.android.server.connectivity.QosCallbackTracker;
|
||||
import com.android.server.connectivity.Vpn;
|
||||
import com.android.server.net.NetworkPinner;
|
||||
import com.android.server.net.NetworkPolicyManagerInternal;
|
||||
@@ -368,6 +376,8 @@ public class ConnectivityServiceTest {
|
||||
private WrappedMultinetworkPolicyTracker mPolicyTracker;
|
||||
private HandlerThread mAlarmManagerThread;
|
||||
private TestNetIdManager mNetIdManager;
|
||||
private QosCallbackMockHelper mQosCallbackMockHelper;
|
||||
private QosCallbackTracker mQosCallbackTracker;
|
||||
|
||||
@Mock DeviceIdleInternal mDeviceIdleInternal;
|
||||
@Mock INetworkManagementService mNetworkManagementService;
|
||||
@@ -1395,6 +1405,7 @@ public class ConnectivityServiceTest {
|
||||
mService.systemReadyInternal();
|
||||
mockVpn(Process.myUid());
|
||||
mCm.bindProcessToNetwork(null);
|
||||
mQosCallbackTracker = mock(QosCallbackTracker.class);
|
||||
|
||||
// Ensure that the default setting for Captive Portals is used for most tests
|
||||
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
||||
@@ -1470,6 +1481,11 @@ public class ConnectivityServiceTest {
|
||||
mEthernetNetworkAgent.disconnect();
|
||||
mEthernetNetworkAgent = null;
|
||||
}
|
||||
|
||||
if (mQosCallbackMockHelper != null) {
|
||||
mQosCallbackMockHelper.tearDown();
|
||||
mQosCallbackMockHelper = null;
|
||||
}
|
||||
mMockVpn.disconnect();
|
||||
waitForIdle();
|
||||
|
||||
@@ -4379,7 +4395,7 @@ public class ConnectivityServiceTest {
|
||||
}
|
||||
|
||||
private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
|
||||
// Ensure the network is disconnected before we do anything.
|
||||
// Ensure the network is disconnected before anything else occurs
|
||||
if (mWiFiNetworkAgent != null) {
|
||||
assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
|
||||
}
|
||||
@@ -8512,7 +8528,7 @@ public class ConnectivityServiceTest {
|
||||
TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
|
||||
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
|
||||
nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
|
||||
0, INVALID_UID);
|
||||
0, INVALID_UID, mQosCallbackTracker);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -8890,7 +8906,7 @@ public class ConnectivityServiceTest {
|
||||
|
||||
@Test
|
||||
public void testInvalidRequestTypes() {
|
||||
final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(),
|
||||
final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
|
||||
NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
|
||||
final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
|
||||
|
||||
@@ -8903,4 +8919,151 @@ public class ConnectivityServiceTest {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class QosCallbackMockHelper {
|
||||
@NonNull public final QosFilter mFilter;
|
||||
@NonNull public final IQosCallback mCallback;
|
||||
@NonNull public final TestNetworkAgentWrapper mAgentWrapper;
|
||||
@NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
|
||||
|
||||
QosCallbackMockHelper() throws Exception {
|
||||
Log.d(TAG, "QosCallbackMockHelper: ");
|
||||
mFilter = mock(QosFilter.class);
|
||||
|
||||
// Ensure the network is disconnected before anything else occurs
|
||||
assertNull(mCellNetworkAgent);
|
||||
|
||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||
mCellNetworkAgent.connect(true);
|
||||
|
||||
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||
waitForIdle();
|
||||
final Network network = mCellNetworkAgent.getNetwork();
|
||||
|
||||
final Pair<IQosCallback, IBinder> pair = createQosCallback();
|
||||
mCallback = pair.first;
|
||||
|
||||
when(mFilter.getNetwork()).thenReturn(network);
|
||||
when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
|
||||
mAgentWrapper = mCellNetworkAgent;
|
||||
}
|
||||
|
||||
void registerQosCallback(@NonNull final QosFilter filter,
|
||||
@NonNull final IQosCallback callback) {
|
||||
mCallbacks.add(callback);
|
||||
final NetworkAgentInfo nai =
|
||||
mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
|
||||
mService.registerQosCallbackInternal(filter, callback, nai);
|
||||
}
|
||||
|
||||
void tearDown() {
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
mService.unregisterQosCallback(mCallbacks.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<IQosCallback, IBinder> createQosCallback() {
|
||||
final IQosCallback callback = mock(IQosCallback.class);
|
||||
final IBinder binder = mock(Binder.class);
|
||||
when(callback.asBinder()).thenReturn(binder);
|
||||
when(binder.isBinderAlive()).thenReturn(true);
|
||||
return new Pair<>(callback, binder);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testQosCallbackRegistration() throws Exception {
|
||||
mQosCallbackMockHelper = new QosCallbackMockHelper();
|
||||
final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
|
||||
|
||||
when(mQosCallbackMockHelper.mFilter.validate())
|
||||
.thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
|
||||
mQosCallbackMockHelper.registerQosCallback(
|
||||
mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
|
||||
|
||||
final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
|
||||
(NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
|
||||
wrapper.getCallbackHistory().poll(1000, x -> true);
|
||||
assertNotNull(cbRegister1);
|
||||
|
||||
final int registerCallbackId = cbRegister1.mQosCallbackId;
|
||||
mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
|
||||
final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
|
||||
cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
|
||||
wrapper.getCallbackHistory().poll(1000, x -> true);
|
||||
assertNotNull(cbUnregister);
|
||||
assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
|
||||
assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
|
||||
mQosCallbackMockHelper = new QosCallbackMockHelper();
|
||||
|
||||
when(mQosCallbackMockHelper.mFilter.validate())
|
||||
.thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
|
||||
mQosCallbackMockHelper.registerQosCallback(
|
||||
mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
|
||||
waitForIdle();
|
||||
verify(mQosCallbackMockHelper.mCallback)
|
||||
.onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQosCallbackAvailableAndLost() throws Exception {
|
||||
mQosCallbackMockHelper = new QosCallbackMockHelper();
|
||||
final int sessionId = 10;
|
||||
final int qosCallbackId = 1;
|
||||
|
||||
when(mQosCallbackMockHelper.mFilter.validate())
|
||||
.thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
|
||||
mQosCallbackMockHelper.registerQosCallback(
|
||||
mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
|
||||
waitForIdle();
|
||||
|
||||
final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
|
||||
1, 2, 3, 4, 5, new ArrayList<>());
|
||||
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
|
||||
.sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
|
||||
waitForIdle();
|
||||
|
||||
verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
|
||||
session.getSessionId() == sessionId
|
||||
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
|
||||
|
||||
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
|
||||
.sendQosSessionLost(qosCallbackId, sessionId);
|
||||
waitForIdle();
|
||||
verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
|
||||
session.getSessionId() == sessionId
|
||||
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQosCallbackTooManyRequests() throws Exception {
|
||||
mQosCallbackMockHelper = new QosCallbackMockHelper();
|
||||
|
||||
when(mQosCallbackMockHelper.mFilter.validate())
|
||||
.thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final Pair<IQosCallback, IBinder> pair = createQosCallback();
|
||||
|
||||
try {
|
||||
mQosCallbackMockHelper.registerQosCallback(
|
||||
mQosCallbackMockHelper.mFilter, pair.first);
|
||||
} catch (ServiceSpecificException e) {
|
||||
assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
|
||||
if (i < 50) {
|
||||
fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
|
||||
}
|
||||
|
||||
// As long as there is at least 50 requests, it is safe to assume it works.
|
||||
// Note: The count isn't being tested precisely against 100 because the counter
|
||||
// is shared with request network.
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail("TOO_MANY_REQUESTS never thrown");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ public class LingerMonitorTest {
|
||||
@Mock Context mCtx;
|
||||
@Mock NetworkNotificationManager mNotifier;
|
||||
@Mock Resources mResources;
|
||||
@Mock QosCallbackTracker mQosCallbackTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -358,7 +359,7 @@ public class LingerMonitorTest {
|
||||
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
|
||||
new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
|
||||
mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
|
||||
Binder.getCallingUid());
|
||||
Binder.getCallingUid(), mQosCallbackTracker);
|
||||
nai.everValidated = true;
|
||||
return nai;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user