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 65 public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { 66 private final NetworkCapabilities mNetworkCapabilities; 67 private final HandlerThread mHandlerThread; 68 private final Context mContext; 69 private final String mLogTag; 70 private final NetworkAgentConfig mNetworkAgentConfig; 71 72 private final ConditionVariable mDisconnected = new ConditionVariable(); 73 private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); 74 private final AtomicBoolean mConnected = new AtomicBoolean(false); 75 private NetworkScore mScore; 76 private NetworkAgent mNetworkAgent; 77 private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; 78 private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; 79 // Controls how test network agent is going to wait before responding to keepalive 80 // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem. 81 private long mKeepaliveResponseDelay = 0L; 82 private Integer mExpectedKeepaliveSlot = null; 83 private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory = 84 new ArrayTrackRecord<CallbackType>().newReadHead(); 85 NetworkAgentWrapper(int transport, LinkProperties linkProperties, NetworkCapabilities ncTemplate, Context context)86 public NetworkAgentWrapper(int transport, LinkProperties linkProperties, 87 NetworkCapabilities ncTemplate, Context context) throws Exception { 88 this(transport, linkProperties, ncTemplate, null /* provider */, context); 89 } 90 NetworkAgentWrapper(int transport, LinkProperties linkProperties, NetworkCapabilities ncTemplate, NetworkProvider provider, Context context)91 public NetworkAgentWrapper(int transport, LinkProperties linkProperties, 92 NetworkCapabilities ncTemplate, NetworkProvider provider, 93 Context context) throws Exception { 94 final int type = transportToLegacyType(transport); 95 final String typeName = ConnectivityManager.getNetworkTypeName(type); 96 mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities(); 97 mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED); 98 mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); 99 mNetworkCapabilities.addTransportType(transport); 100 switch (transport) { 101 case TRANSPORT_ETHERNET: 102 mScore = new NetworkScore.Builder().setLegacyInt(70).build(); 103 break; 104 case TRANSPORT_WIFI: 105 mScore = new NetworkScore.Builder().setLegacyInt(60).build(); 106 break; 107 case TRANSPORT_CELLULAR: 108 mScore = new NetworkScore.Builder().setLegacyInt(50).build(); 109 break; 110 case TRANSPORT_WIFI_AWARE: 111 mScore = new NetworkScore.Builder().setLegacyInt(20).build(); 112 break; 113 case TRANSPORT_TEST: 114 mScore = new NetworkScore.Builder().build(); 115 break; 116 case TRANSPORT_VPN: 117 mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); 118 // VPNs deduce the SUSPENDED capability from their underlying networks and there 119 // is no public API to let VPN services set it. 120 mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); 121 mScore = new NetworkScore.Builder().setLegacyInt(101).build(); 122 break; 123 default: 124 throw new UnsupportedOperationException("unimplemented network type"); 125 } 126 mContext = context; 127 mLogTag = "Mock-" + typeName; 128 mHandlerThread = new HandlerThread(mLogTag); 129 mHandlerThread.start(); 130 131 // extraInfo is set to "" by default in NetworkAgentConfig. 132 final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : ""; 133 mNetworkAgentConfig = new NetworkAgentConfig.Builder() 134 .setLegacyType(type) 135 .setLegacyTypeName(typeName) 136 .setLegacyExtraInfo(extraInfo) 137 .build(); 138 mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig, provider); 139 } 140 makeNetworkAgent(LinkProperties linkProperties, final NetworkAgentConfig nac, NetworkProvider provider)141 protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties, 142 final NetworkAgentConfig nac, NetworkProvider provider) throws Exception { 143 return new InstrumentedNetworkAgent(this, linkProperties, nac, provider); 144 } 145 146 public static class InstrumentedNetworkAgent extends NetworkAgent { 147 private final NetworkAgentWrapper mWrapper; 148 private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider"; 149 InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, NetworkAgentConfig nac)150 public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, 151 NetworkAgentConfig nac) { 152 this(wrapper, lp, nac, null /* provider */); 153 } 154 InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, NetworkAgentConfig nac, NetworkProvider provider)155 public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, 156 NetworkAgentConfig nac, NetworkProvider provider) { 157 super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag, 158 wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac, 159 null != provider ? provider : new NetworkProvider(wrapper.mContext, 160 wrapper.mHandlerThread.getLooper(), PROVIDER_NAME)); 161 mWrapper = wrapper; 162 register(); 163 } 164 165 @Override unwanted()166 public void unwanted() { 167 mWrapper.mDisconnected.open(); 168 } 169 170 @Override startSocketKeepalive(Message msg)171 public void startSocketKeepalive(Message msg) { 172 int slot = msg.arg1; 173 if (mWrapper.mExpectedKeepaliveSlot != null) { 174 assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot); 175 } 176 mWrapper.mHandlerThread.getThreadHandler().postDelayed( 177 () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError), 178 mWrapper.mKeepaliveResponseDelay); 179 } 180 181 @Override stopSocketKeepalive(Message msg)182 public void stopSocketKeepalive(Message msg) { 183 final int slot = msg.arg1; 184 mWrapper.mHandlerThread.getThreadHandler().postDelayed( 185 () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError), 186 mWrapper.mKeepaliveResponseDelay); 187 } 188 189 @Override onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter)190 public void onQosCallbackRegistered(final int qosCallbackId, 191 final @NonNull QosFilter filter) { 192 Log.i(mWrapper.mLogTag, "onQosCallbackRegistered"); 193 mWrapper.mCallbackHistory.add( 194 new CallbackType.OnQosCallbackRegister(qosCallbackId, filter)); 195 } 196 197 @Override onQosCallbackUnregistered(final int qosCallbackId)198 public void onQosCallbackUnregistered(final int qosCallbackId) { 199 Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered"); 200 mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId)); 201 } 202 203 @Override preventAutomaticReconnect()204 protected void preventAutomaticReconnect() { 205 mWrapper.mPreventReconnectReceived.open(); 206 } 207 208 @Override addKeepalivePacketFilter(Message msg)209 protected void addKeepalivePacketFilter(Message msg) { 210 Log.i(mWrapper.mLogTag, "Add keepalive packet filter."); 211 } 212 213 @Override removeKeepalivePacketFilter(Message msg)214 protected void removeKeepalivePacketFilter(Message msg) { 215 Log.i(mWrapper.mLogTag, "Remove keepalive packet filter."); 216 } 217 } 218 setScore(@onNull final NetworkScore score)219 public void setScore(@NonNull final NetworkScore score) { 220 mScore = score; 221 mNetworkAgent.sendNetworkScore(score); 222 } 223 adjustScore(int change)224 public void adjustScore(int change) { 225 final int newLegacyScore = mScore.getLegacyInt() + change; 226 final NetworkScore.Builder builder = new NetworkScore.Builder() 227 .setLegacyInt(newLegacyScore); 228 if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI) && newLegacyScore < 50) { 229 builder.setExiting(true); 230 } 231 mScore = builder.build(); 232 mNetworkAgent.sendNetworkScore(mScore); 233 } 234 getScore()235 public NetworkScore getScore() { 236 return mScore; 237 } 238 explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated)239 public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { 240 mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated); 241 } 242 addCapability(int capability)243 public void addCapability(int capability) { 244 mNetworkCapabilities.addCapability(capability); 245 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 246 } 247 removeCapability(int capability)248 public void removeCapability(int capability) { 249 mNetworkCapabilities.removeCapability(capability); 250 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 251 } 252 setUids(Set<Range<Integer>> uids)253 public void setUids(Set<Range<Integer>> uids) { 254 mNetworkCapabilities.setUids(uids); 255 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 256 } 257 setSignalStrength(int signalStrength)258 public void setSignalStrength(int signalStrength) { 259 mNetworkCapabilities.setSignalStrength(signalStrength); 260 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 261 } 262 setNetworkSpecifier(NetworkSpecifier networkSpecifier)263 public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) { 264 mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); 265 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 266 } 267 setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService)268 public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) { 269 mNetworkCapabilities.set(nc); 270 if (sendToConnectivityService) { 271 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 272 } 273 } 274 setUnderlyingNetworks(List<Network> underlyingNetworks)275 public void setUnderlyingNetworks(List<Network> underlyingNetworks) { 276 mNetworkAgent.setUnderlyingNetworks(underlyingNetworks); 277 } 278 setOwnerUid(int uid)279 public void setOwnerUid(int uid) { 280 mNetworkCapabilities.setOwnerUid(uid); 281 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 282 } 283 connect()284 public void connect() { 285 if (!mConnected.compareAndSet(false /* expect */, true /* update */)) { 286 // compareAndSet returns false when the value couldn't be updated because it did not 287 // match the expected value. 288 fail("Test NetworkAgents can only be connected once"); 289 } 290 mNetworkAgent.markConnected(); 291 } 292 suspend()293 public void suspend() { 294 removeCapability(NET_CAPABILITY_NOT_SUSPENDED); 295 } 296 resume()297 public void resume() { 298 addCapability(NET_CAPABILITY_NOT_SUSPENDED); 299 } 300 disconnect()301 public void disconnect() { 302 mNetworkAgent.unregister(); 303 } 304 305 @Override getNetwork()306 public Network getNetwork() { 307 return mNetworkAgent.getNetwork(); 308 } 309 expectPreventReconnectReceived(long timeoutMs)310 public void expectPreventReconnectReceived(long timeoutMs) { 311 assertTrue(mPreventReconnectReceived.block(timeoutMs)); 312 } 313 expectDisconnected(long timeoutMs)314 public void expectDisconnected(long timeoutMs) { 315 assertTrue(mDisconnected.block(timeoutMs)); 316 } 317 assertNotDisconnected(long timeoutMs)318 public void assertNotDisconnected(long timeoutMs) { 319 assertFalse(mDisconnected.block(timeoutMs)); 320 } 321 sendLinkProperties(LinkProperties lp)322 public void sendLinkProperties(LinkProperties lp) { 323 mNetworkAgent.sendLinkProperties(lp); 324 } 325 setStartKeepaliveEvent(int reason)326 public void setStartKeepaliveEvent(int reason) { 327 mStartKeepaliveError = reason; 328 } 329 setStopKeepaliveEvent(int reason)330 public void setStopKeepaliveEvent(int reason) { 331 mStopKeepaliveError = reason; 332 } 333 setKeepaliveResponseDelay(long delay)334 public void setKeepaliveResponseDelay(long delay) { 335 mKeepaliveResponseDelay = delay; 336 } 337 setExpectedKeepaliveSlot(Integer slot)338 public void setExpectedKeepaliveSlot(Integer slot) { 339 mExpectedKeepaliveSlot = slot; 340 } 341 getNetworkAgent()342 public NetworkAgent getNetworkAgent() { 343 return mNetworkAgent; 344 } 345 getNetworkAgentConfig()346 public NetworkAgentConfig getNetworkAgentConfig() { 347 return mNetworkAgentConfig; 348 } 349 getNetworkCapabilities()350 public NetworkCapabilities getNetworkCapabilities() { 351 return mNetworkCapabilities; 352 } 353 getLegacyType()354 public int getLegacyType() { 355 return mNetworkAgentConfig.getLegacyType(); 356 } 357 getExtraInfo()358 public String getExtraInfo() { 359 return mNetworkAgentConfig.getLegacyExtraInfo(); 360 } 361 getCallbackHistory()362 public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() { 363 return mCallbackHistory; 364 } 365 waitForIdle(long timeoutMs)366 public void waitForIdle(long timeoutMs) { 367 HandlerUtils.waitForIdle(mHandlerThread, timeoutMs); 368 } 369 370 abstract static class CallbackType { 371 final int mQosCallbackId; 372 CallbackType(final int qosCallbackId)373 protected CallbackType(final int qosCallbackId) { 374 mQosCallbackId = qosCallbackId; 375 } 376 377 static class OnQosCallbackRegister extends CallbackType { 378 final QosFilter mFilter; OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter)379 OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) { 380 super(qosCallbackId); 381 mFilter = filter; 382 } 383 384 @Override equals(final Object o)385 public boolean equals(final Object o) { 386 if (this == o) return true; 387 if (o == null || getClass() != o.getClass()) return false; 388 final OnQosCallbackRegister that = (OnQosCallbackRegister) o; 389 return mQosCallbackId == that.mQosCallbackId 390 && Objects.equals(mFilter, that.mFilter); 391 } 392 393 @Override hashCode()394 public int hashCode() { 395 return Objects.hash(mQosCallbackId, mFilter); 396 } 397 } 398 399 static class OnQosCallbackUnregister extends CallbackType { OnQosCallbackUnregister(final int qosCallbackId)400 OnQosCallbackUnregister(final int qosCallbackId) { 401 super(qosCallbackId); 402 } 403 404 @Override equals(final Object o)405 public boolean equals(final Object o) { 406 if (this == o) return true; 407 if (o == null || getClass() != o.getClass()) return false; 408 final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o; 409 return mQosCallbackId == that.mQosCallbackId; 410 } 411 412 @Override hashCode()413 public int hashCode() { 414 return Objects.hash(mQosCallbackId); 415 } 416 } 417 } 418 isBypassableVpn()419 public boolean isBypassableVpn() { 420 return mNetworkAgentConfig.isBypassableVpn(); 421 } 422 } 423