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