1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 22 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 23 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 24 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 25 import static android.net.NetworkCapabilities.TRANSPORT_VPN; 26 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 27 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; 28 29 import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType; 30 31 import static junit.framework.Assert.assertFalse; 32 import static junit.framework.Assert.assertTrue; 33 34 import static org.junit.Assert.assertEquals; 35 import static org.junit.Assert.fail; 36 37 import android.annotation.NonNull; 38 import android.content.Context; 39 import android.net.ConnectivityManager; 40 import android.net.LinkProperties; 41 import android.net.Network; 42 import android.net.NetworkAgent; 43 import android.net.NetworkAgentConfig; 44 import android.net.NetworkCapabilities; 45 import android.net.NetworkProvider; 46 import android.net.NetworkScore; 47 import android.net.NetworkSpecifier; 48 import android.net.QosFilter; 49 import android.net.SocketKeepalive; 50 import android.os.ConditionVariable; 51 import android.os.HandlerThread; 52 import android.os.Message; 53 import android.util.Log; 54 import android.util.Range; 55 56 import com.android.net.module.util.ArrayTrackRecord; 57 import com.android.testutils.HandlerUtils; 58 import com.android.testutils.TestableNetworkCallback; 59 60 import java.util.List; 61 import java.util.Objects; 62 import java.util.Set; 63 import java.util.concurrent.atomic.AtomicBoolean; 64 import java.util.function.Consumer; 65 66 public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { 67 private final NetworkCapabilities mNetworkCapabilities; 68 private final HandlerThread mHandlerThread; 69 private final Context mContext; 70 private final String mLogTag; 71 private final NetworkAgentConfig mNetworkAgentConfig; 72 73 private final ConditionVariable mDisconnected = new ConditionVariable(); 74 private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); 75 private final AtomicBoolean mConnected = new AtomicBoolean(false); 76 private NetworkScore mScore; 77 private NetworkAgent mNetworkAgent; 78 private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; 79 private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; 80 // Controls how test network agent is going to wait before responding to keepalive 81 // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem. 82 private long mKeepaliveResponseDelay = 0L; 83 private Integer mExpectedKeepaliveSlot = null; 84 private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory = 85 new ArrayTrackRecord<CallbackType>().newReadHead(); 86 87 public static class Callbacks { 88 public final Consumer<NetworkAgent> onNetworkCreated; 89 public final Consumer<NetworkAgent> onNetworkUnwanted; 90 public final Consumer<NetworkAgent> onNetworkDestroyed; 91 Callbacks()92 public Callbacks() { 93 this(null, null, null); 94 } 95 Callbacks(Consumer<NetworkAgent> onNetworkCreated, Consumer<NetworkAgent> onNetworkUnwanted, Consumer<NetworkAgent> onNetworkDestroyed)96 public Callbacks(Consumer<NetworkAgent> onNetworkCreated, 97 Consumer<NetworkAgent> onNetworkUnwanted, 98 Consumer<NetworkAgent> onNetworkDestroyed) { 99 this.onNetworkCreated = onNetworkCreated; 100 this.onNetworkUnwanted = onNetworkUnwanted; 101 this.onNetworkDestroyed = onNetworkDestroyed; 102 } 103 } 104 105 private final Callbacks mCallbacks; 106 NetworkAgentWrapper(int transport, LinkProperties linkProperties, NetworkCapabilities ncTemplate, Context context)107 public NetworkAgentWrapper(int transport, LinkProperties linkProperties, 108 NetworkCapabilities ncTemplate, Context context) throws Exception { 109 this(transport, linkProperties, ncTemplate, null /* provider */, 110 null /* callbacks */, context); 111 } 112 NetworkAgentWrapper(int transport, LinkProperties linkProperties, NetworkCapabilities ncTemplate, NetworkProvider provider, Callbacks callbacks, Context context)113 public NetworkAgentWrapper(int transport, LinkProperties linkProperties, 114 NetworkCapabilities ncTemplate, NetworkProvider provider, 115 Callbacks callbacks, Context context) throws Exception { 116 final int type = transportToLegacyType(transport); 117 final String typeName = ConnectivityManager.getNetworkTypeName(type); 118 mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities(); 119 mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED); 120 mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); 121 mNetworkCapabilities.addTransportType(transport); 122 switch (transport) { 123 case TRANSPORT_ETHERNET: 124 mScore = new NetworkScore.Builder().setLegacyInt(70).build(); 125 break; 126 case TRANSPORT_WIFI: 127 mScore = new NetworkScore.Builder().setLegacyInt(60).build(); 128 break; 129 case TRANSPORT_CELLULAR: 130 mScore = new NetworkScore.Builder().setLegacyInt(50).build(); 131 break; 132 case TRANSPORT_WIFI_AWARE: 133 mScore = new NetworkScore.Builder().setLegacyInt(20).build(); 134 break; 135 case TRANSPORT_TEST: 136 mScore = new NetworkScore.Builder().build(); 137 break; 138 case TRANSPORT_VPN: 139 mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); 140 // VPNs deduce the SUSPENDED capability from their underlying networks and there 141 // is no public API to let VPN services set it. 142 mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); 143 mScore = new NetworkScore.Builder().setLegacyInt(101).build(); 144 break; 145 default: 146 throw new UnsupportedOperationException("unimplemented network type"); 147 } 148 mContext = context; 149 mLogTag = "Mock-" + typeName; 150 mHandlerThread = new HandlerThread(mLogTag); 151 mHandlerThread.start(); 152 153 // extraInfo is set to "" by default in NetworkAgentConfig. 154 final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : ""; 155 mNetworkAgentConfig = new NetworkAgentConfig.Builder() 156 .setLegacyType(type) 157 .setLegacyTypeName(typeName) 158 .setLegacyExtraInfo(extraInfo) 159 .build(); 160 mCallbacks = (callbacks != null) ? callbacks : new Callbacks(); 161 mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig, provider); 162 } 163 makeNetworkAgent(LinkProperties linkProperties, final NetworkAgentConfig nac, NetworkProvider provider)164 protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties, 165 final NetworkAgentConfig nac, NetworkProvider provider) throws Exception { 166 return new InstrumentedNetworkAgent(this, linkProperties, nac, provider); 167 } 168 169 public static class InstrumentedNetworkAgent extends NetworkAgent { 170 private final NetworkAgentWrapper mWrapper; 171 private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider"; 172 InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, NetworkAgentConfig nac)173 public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, 174 NetworkAgentConfig nac) { 175 this(wrapper, lp, nac, null /* provider */); 176 } 177 InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, NetworkAgentConfig nac, NetworkProvider provider)178 public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, 179 NetworkAgentConfig nac, NetworkProvider provider) { 180 super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag, 181 wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac, 182 null != provider ? provider : new NetworkProvider(wrapper.mContext, 183 wrapper.mHandlerThread.getLooper(), PROVIDER_NAME)); 184 mWrapper = wrapper; 185 register(); 186 } 187 188 @Override unwanted()189 public void unwanted() { 190 mWrapper.mDisconnected.open(); 191 } 192 193 @Override startSocketKeepalive(Message msg)194 public void startSocketKeepalive(Message msg) { 195 int slot = msg.arg1; 196 if (mWrapper.mExpectedKeepaliveSlot != null) { 197 assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot); 198 } 199 mWrapper.mHandlerThread.getThreadHandler().postDelayed( 200 () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError), 201 mWrapper.mKeepaliveResponseDelay); 202 } 203 204 @Override stopSocketKeepalive(Message msg)205 public void stopSocketKeepalive(Message msg) { 206 final int slot = msg.arg1; 207 mWrapper.mHandlerThread.getThreadHandler().postDelayed( 208 () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError), 209 mWrapper.mKeepaliveResponseDelay); 210 } 211 212 @Override onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter)213 public void onQosCallbackRegistered(final int qosCallbackId, 214 final @NonNull QosFilter filter) { 215 Log.i(mWrapper.mLogTag, "onQosCallbackRegistered"); 216 mWrapper.mCallbackHistory.add( 217 new CallbackType.OnQosCallbackRegister(qosCallbackId, filter)); 218 } 219 220 @Override onQosCallbackUnregistered(final int qosCallbackId)221 public void onQosCallbackUnregistered(final int qosCallbackId) { 222 Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered"); 223 mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId)); 224 } 225 226 @Override preventAutomaticReconnect()227 protected void preventAutomaticReconnect() { 228 mWrapper.mPreventReconnectReceived.open(); 229 } 230 231 @Override addKeepalivePacketFilter(Message msg)232 protected void addKeepalivePacketFilter(Message msg) { 233 Log.i(mWrapper.mLogTag, "Add keepalive packet filter."); 234 } 235 236 @Override removeKeepalivePacketFilter(Message msg)237 protected void removeKeepalivePacketFilter(Message msg) { 238 Log.i(mWrapper.mLogTag, "Remove keepalive packet filter."); 239 } 240 241 @Override onNetworkCreated()242 public void onNetworkCreated() { 243 super.onNetworkCreated(); 244 if (mWrapper.mCallbacks.onNetworkCreated != null) { 245 mWrapper.mCallbacks.onNetworkCreated.accept(this); 246 } 247 } 248 249 @Override onNetworkUnwanted()250 public void onNetworkUnwanted() { 251 super.onNetworkUnwanted(); 252 if (mWrapper.mCallbacks.onNetworkUnwanted != null) { 253 mWrapper.mCallbacks.onNetworkUnwanted.accept(this); 254 } 255 } 256 257 @Override onNetworkDestroyed()258 public void onNetworkDestroyed() { 259 super.onNetworkDestroyed(); 260 if (mWrapper.mCallbacks.onNetworkDestroyed != null) { 261 mWrapper.mCallbacks.onNetworkDestroyed.accept(this); 262 } 263 } 264 265 } 266 setScore(@onNull final NetworkScore score)267 public void setScore(@NonNull final NetworkScore score) { 268 mScore = score; 269 mNetworkAgent.sendNetworkScore(score); 270 } 271 272 // TODO : remove adjustScore and replace with the appropriate exiting flags. adjustScore(int change)273 public void adjustScore(int change) { 274 final int newLegacyScore = mScore.getLegacyInt() + change; 275 final NetworkScore.Builder builder = new NetworkScore.Builder() 276 .setLegacyInt(newLegacyScore); 277 if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI) && newLegacyScore < 50) { 278 builder.setExiting(true); 279 } 280 mScore = builder.build(); 281 mNetworkAgent.sendNetworkScore(mScore); 282 } 283 getScore()284 public NetworkScore getScore() { 285 return mScore; 286 } 287 explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated)288 public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { 289 mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated); 290 } 291 addCapability(int capability)292 public void addCapability(int capability) { 293 mNetworkCapabilities.addCapability(capability); 294 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 295 } 296 removeCapability(int capability)297 public void removeCapability(int capability) { 298 mNetworkCapabilities.removeCapability(capability); 299 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 300 } 301 setUids(Set<Range<Integer>> uids)302 public void setUids(Set<Range<Integer>> uids) { 303 mNetworkCapabilities.setUids(uids); 304 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 305 } 306 setSignalStrength(int signalStrength)307 public void setSignalStrength(int signalStrength) { 308 mNetworkCapabilities.setSignalStrength(signalStrength); 309 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 310 } 311 setNetworkSpecifier(NetworkSpecifier networkSpecifier)312 public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) { 313 mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); 314 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 315 } 316 setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService)317 public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) { 318 mNetworkCapabilities.set(nc); 319 if (sendToConnectivityService) { 320 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 321 } 322 } 323 setUnderlyingNetworks(List<Network> underlyingNetworks)324 public void setUnderlyingNetworks(List<Network> underlyingNetworks) { 325 mNetworkAgent.setUnderlyingNetworks(underlyingNetworks); 326 } 327 setOwnerUid(int uid)328 public void setOwnerUid(int uid) { 329 mNetworkCapabilities.setOwnerUid(uid); 330 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 331 } 332 connect()333 public void connect() { 334 if (!mConnected.compareAndSet(false /* expect */, true /* update */)) { 335 // compareAndSet returns false when the value couldn't be updated because it did not 336 // match the expected value. 337 fail("Test NetworkAgents can only be connected once"); 338 } 339 mNetworkAgent.markConnected(); 340 } 341 suspend()342 public void suspend() { 343 removeCapability(NET_CAPABILITY_NOT_SUSPENDED); 344 } 345 resume()346 public void resume() { 347 addCapability(NET_CAPABILITY_NOT_SUSPENDED); 348 } 349 disconnect()350 public void disconnect() { 351 mNetworkAgent.unregister(); 352 } 353 354 @Override getNetwork()355 public Network getNetwork() { 356 return mNetworkAgent.getNetwork(); 357 } 358 expectPreventReconnectReceived(long timeoutMs)359 public void expectPreventReconnectReceived(long timeoutMs) { 360 assertTrue(mPreventReconnectReceived.block(timeoutMs)); 361 } 362 expectDisconnected(long timeoutMs)363 public void expectDisconnected(long timeoutMs) { 364 assertTrue(mDisconnected.block(timeoutMs)); 365 } 366 assertNotDisconnected(long timeoutMs)367 public void assertNotDisconnected(long timeoutMs) { 368 assertFalse(mDisconnected.block(timeoutMs)); 369 } 370 sendLinkProperties(LinkProperties lp)371 public void sendLinkProperties(LinkProperties lp) { 372 mNetworkAgent.sendLinkProperties(lp); 373 } 374 setStartKeepaliveEvent(int reason)375 public void setStartKeepaliveEvent(int reason) { 376 mStartKeepaliveError = reason; 377 } 378 setStopKeepaliveEvent(int reason)379 public void setStopKeepaliveEvent(int reason) { 380 mStopKeepaliveError = reason; 381 } 382 setKeepaliveResponseDelay(long delay)383 public void setKeepaliveResponseDelay(long delay) { 384 mKeepaliveResponseDelay = delay; 385 } 386 setExpectedKeepaliveSlot(Integer slot)387 public void setExpectedKeepaliveSlot(Integer slot) { 388 mExpectedKeepaliveSlot = slot; 389 } 390 getNetworkAgent()391 public NetworkAgent getNetworkAgent() { 392 return mNetworkAgent; 393 } 394 getNetworkAgentConfig()395 public NetworkAgentConfig getNetworkAgentConfig() { 396 return mNetworkAgentConfig; 397 } 398 getNetworkCapabilities()399 public NetworkCapabilities getNetworkCapabilities() { 400 return mNetworkCapabilities; 401 } 402 getLegacyType()403 public int getLegacyType() { 404 return mNetworkAgentConfig.getLegacyType(); 405 } 406 getExtraInfo()407 public String getExtraInfo() { 408 return mNetworkAgentConfig.getLegacyExtraInfo(); 409 } 410 getCallbackHistory()411 public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() { 412 return mCallbackHistory; 413 } 414 waitForIdle(long timeoutMs)415 public void waitForIdle(long timeoutMs) { 416 HandlerUtils.waitForIdle(mHandlerThread, timeoutMs); 417 } 418 419 abstract static class CallbackType { 420 final int mQosCallbackId; 421 CallbackType(final int qosCallbackId)422 protected CallbackType(final int qosCallbackId) { 423 mQosCallbackId = qosCallbackId; 424 } 425 426 static class OnQosCallbackRegister extends CallbackType { 427 final QosFilter mFilter; OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter)428 OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) { 429 super(qosCallbackId); 430 mFilter = filter; 431 } 432 433 @Override equals(final Object o)434 public boolean equals(final Object o) { 435 if (this == o) return true; 436 if (o == null || getClass() != o.getClass()) return false; 437 final OnQosCallbackRegister that = (OnQosCallbackRegister) o; 438 return mQosCallbackId == that.mQosCallbackId 439 && Objects.equals(mFilter, that.mFilter); 440 } 441 442 @Override hashCode()443 public int hashCode() { 444 return Objects.hash(mQosCallbackId, mFilter); 445 } 446 } 447 448 static class OnQosCallbackUnregister extends CallbackType { OnQosCallbackUnregister(final int qosCallbackId)449 OnQosCallbackUnregister(final int qosCallbackId) { 450 super(qosCallbackId); 451 } 452 453 @Override equals(final Object o)454 public boolean equals(final Object o) { 455 if (this == o) return true; 456 if (o == null || getClass() != o.getClass()) return false; 457 final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o; 458 return mQosCallbackId == that.mQosCallbackId; 459 } 460 461 @Override hashCode()462 public int hashCode() { 463 return Objects.hash(mQosCallbackId); 464 } 465 } 466 } 467 isBypassableVpn()468 public boolean isBypassableVpn() { 469 return mNetworkAgentConfig.isBypassableVpn(); 470 } 471 } 472