Loading src/java/com/android/internal/telephony/dataconnection/ApnContext.java +11 −12 Original line number Diff line number Diff line Loading @@ -32,12 +32,13 @@ import com.android.internal.R; import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -412,19 +413,21 @@ public class ApnContext { } } public void requestNetwork(NetworkRequest networkRequest, LocalLog log) { public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) { log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size()); } else { mLocalLogs.add(log); mNetworkRequests.add(networkRequest); mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType)); mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); } } } public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log) == false) { log.log("ApnContext.releaseNetwork can't find this log"); Loading @@ -438,19 +441,15 @@ public class ApnContext { mNetworkRequests.remove(networkRequest); log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() + " requests."); if (mNetworkRequests.size() == 0) { mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType)); if (mNetworkRequests.size() == 0 || type == DcTracker.RELEASE_TYPE_DETACH || type == DcTracker.RELEASE_TYPE_HANDOVER) { mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); } } } } public List<NetworkRequest> getNetworkRequests() { synchronized (mRefCountLock) { return new ArrayList<NetworkRequest>(mNetworkRequests); } } /** * @param excludeDun True if excluding requests that have DUN capability * @return True if the attached network requests contain restricted capability. Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +145 −49 Original line number Diff line number Diff line Loading @@ -129,14 +129,16 @@ public class DataConnection extends StateMachine { int mRilRat; Message mOnCompletedMsg; final int mConnectionGeneration; final boolean mIsHandover; ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { Message onCompletedMsg, int connectionGeneration, boolean isHandover) { mApnContext = apnContext; mProfileId = profileId; mRilRat = rilRadioTechnology; mOnCompletedMsg = onCompletedMsg; mConnectionGeneration = connectionGeneration; mIsHandover = isHandover; } @Override Loading @@ -144,7 +146,9 @@ public class DataConnection extends StateMachine { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mProfileId=" + mProfileId + " mRat=" + mRilRat + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + " mIsHandover=" + mIsHandover + "}"; } } Loading @@ -155,11 +159,14 @@ public class DataConnection extends StateMachine { int mTag; public ApnContext mApnContext; String mReason; final boolean mIsHandover; Message mOnCompletedMsg; DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) { DisconnectParams(ApnContext apnContext, String reason, boolean isHandover, Message onCompletedMsg) { mApnContext = apnContext; mReason = reason; mIsHandover = isHandover; mOnCompletedMsg = onCompletedMsg; } Loading @@ -167,6 +174,7 @@ public class DataConnection extends StateMachine { public String toString() { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mReason=" + mReason + " mIsHandover=" + mIsHandover + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; } } Loading Loading @@ -286,9 +294,12 @@ public class DataConnection extends StateMachine { DataServiceManager dataServiceManager, DcTesterFailBringUpAll failBringUpAll, DcController dcc) { String transportType = (dataServiceManager.getTransportType() == TransportType.WWAN) ? "C" // Cellular : "I"; // IWLAN DataConnection dc = new DataConnection(phone, "DC-" + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, dcc); "DC-" + transportType + "-" + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, dcc); dc.start(); if (DBG) dc.log("Made " + dc.getName()); return dc; Loading Loading @@ -498,21 +509,35 @@ public class DataConnection extends StateMachine { setInitialState(mInactiveState); } /** * Get the DcTracker for handover. There are multiple DcTrackers for different transports (e.g. * WWAN, WLAN). For data handover, we need to handover the existing data connection from current * DcTracker to the DcTracker on another transport. */ private DcTracker getHandoverDcTracker() { int transportType = mDataServiceManager.getTransportType(); // Get the DcTracker from the other transport. return mPhone.getDcTracker(transportType == TransportType.WWAN ? TransportType.WLAN : TransportType.WWAN); } /** * Begin setting up a data connection, calls setupDataCall * and the ConnectionParams will be returned with the * EVENT_SETUP_DATA_CONNECTION_DONE * * @param cp is the connection parameters * * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success. */ private void onConnect(ConnectionParams cp) { private @DataFailCause.FailCause int connect(ConnectionParams cp) { if (DBG) { log("onConnect: carrier='" + mApnSetting.getEntryName() log("connect: carrier='" + mApnSetting.getEntryName() + "' APN='" + mApnSetting.getApnName() + "' proxy='" + mApnSetting.getProxyAddressAsString() + "' port='" + mApnSetting.getProxyPort() + "'"); } if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.onConnect"); if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.connect"); // Check if we should fake an error. if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { Loading @@ -525,11 +550,11 @@ public class DataConnection extends StateMachine { AsyncResult.forMessage(msg, response, null); sendMessage(msg); if (DBG) { log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() + " send error response=" + response); } mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; return; return DataFailCause.NONE; } mCreateTime = -1; Loading @@ -553,11 +578,46 @@ public class DataConnection extends StateMachine { boolean allowRoaming = mPhone.getDataRoamingEnabled() || (isModemRoaming && !mPhone.getServiceState().getDataRoaming()); // Check if this data setup is a handover. LinkProperties linkProperties = null; int reason = DataService.REQUEST_REASON_NORMAL; if (cp.mIsHandover) { // If this is a data setup for handover, we need to pass the link properties // of the existing data connection to the modem. DcTracker dcTracker = getHandoverDcTracker(); if (dcTracker == null || cp.mApnContext == null) { loge("connect: Handover failed. dcTracker=" + dcTracker + ", apnContext=" + cp.mApnContext); return DataFailCause.HANDOVER_FAILED; } DataConnection dc = dcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType()); if (dc == null) { loge("connect: Can't find data connection for handover."); return DataFailCause.HANDOVER_FAILED; } linkProperties = dc.getLinkProperties(); if (linkProperties == null) { loge("connect: Can't find link properties of handover data connection. dc=" + dc); return DataFailCause.HANDOVER_FAILED; } reason = DataService.REQUEST_REASON_HANDOVER; } mDataServiceManager.setupDataCall( ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), dp, isModemRoaming, allowRoaming, DataService.REQUEST_REASON_NORMAL, null, msg); ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), dp, isModemRoaming, allowRoaming, reason, linkProperties, msg); TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, dp.getProfileId(), dp.getApn(), dp.getProtocol()); return DataFailCause.NONE; } public void onSubscriptionOverride(int overrideMask, int overrideValue) { Loading @@ -581,6 +641,8 @@ public class DataConnection extends StateMachine { if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF) || TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { discReason = DataService.REQUEST_REASON_SHUTDOWN; } else if (dp.mIsHandover) { discReason = DataService.REQUEST_REASON_HANDOVER; } } Loading @@ -599,7 +661,7 @@ public class DataConnection extends StateMachine { if (apnContext == alreadySent) continue; if (reason != null) apnContext.setReason(reason); Pair<ApnContext, Integer> pair = new Pair<>(apnContext, cp.mConnectionGeneration); Message msg = mDct.obtainMessage(event, pair); Message msg = mDct.obtainMessage(event, mCid, cp.mIsHandover ? 1 : 0, pair); AsyncResult.forMessage(msg); msg.sendToTarget(); } Loading @@ -624,6 +686,7 @@ public class DataConnection extends StateMachine { long timeStamp = System.currentTimeMillis(); connectionCompletedMsg.arg1 = mCid; connectionCompletedMsg.arg2 = cp.mIsHandover ? 1 : 0; if (cause == DataFailCause.NONE) { mCreateTime = timeStamp; Loading Loading @@ -746,6 +809,7 @@ public class DataConnection extends StateMachine { ConnectionParams cp) { SetupResult result; log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response); if (cp.mTag != mTag) { if (DBG) { log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); Loading Loading @@ -1512,8 +1576,6 @@ public class DataConnection extends StateMachine { @Override public boolean processMessage(Message msg) { boolean retVal; switch (msg.what) { case EVENT_RESET: case EVENT_REEVALUATE_RESTRICTED_STATE: Loading @@ -1521,45 +1583,43 @@ public class DataConnection extends StateMachine { log("DcInactiveState: msg.what=" + getWhatToString(msg.what) + ", ignore we're already done"); } retVal = HANDLED; break; return HANDLED; case EVENT_CONNECT: if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); ConnectionParams cp = (ConnectionParams) msg.obj; if (initConnection(cp)) { onConnect(mConnectionParams); transitionTo(mActivatingState); } else { if (DBG) { if (!initConnection(cp)) { log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); } notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, false); transitionTo(mInactiveState); return HANDLED; } retVal = HANDLED; break; int cause = connect(cp); if (cause != DataFailCause.NONE) { log("DcInactiveState: msg.what=EVENT_CONNECT connect failed"); notifyConnectCompleted(cp, cause, false); transitionTo(mInactiveState); return HANDLED; } transitionTo(mActivatingState); return HANDLED; case EVENT_DISCONNECT: if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); notifyDisconnectCompleted((DisconnectParams)msg.obj, false); retVal = HANDLED; break; return HANDLED; case EVENT_DISCONNECT_ALL: if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); notifyDisconnectCompleted((DisconnectParams)msg.obj, false); retVal = HANDLED; break; return HANDLED; default: if (VDBG) { log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what)); } retVal = NOT_HANDLED; break; return NOT_HANDLED; } return retVal; } } private DcInactiveState mInactiveState = new DcInactiveState(); Loading Loading @@ -1728,9 +1788,30 @@ public class DataConnection extends StateMachine { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); } if (mConnectionParams != null && mConnectionParams.mIsHandover) { // If this is a data setup for handover, we need to reuse the existing network agent // instead of creating a new one. This should be transparent to connectivity // service. DcTracker dcTracker = getHandoverDcTracker(); DataConnection dc = dcTracker.getDataConnectionByApnType( mConnectionParams.mApnContext.getApnType()); if (dc != null) { mNetworkAgent = dc.getNetworkAgent(); if (mNetworkAgent != null) { mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); mNetworkAgent.sendLinkProperties(mLinkProperties); } else { loge("Failed to get network agent from original data connection " + dc); } } else { loge("Cannot find the data connection for handover."); } } else { mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties, 50, misc); } if (mDataServiceManager.getTransportType() == TransportType.WWAN) { mPhone.mCi.registerForNattKeepaliveStatus( getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null); Loading Loading @@ -1761,7 +1842,13 @@ public class DataConnection extends StateMachine { mPhone.mCi.unregisterForLceInfo(getHandler()); } if (mNetworkAgent != null) { // We do not want to update the network info if this is a handover. For all other // cases we need to update connectivity service with the latest network info. // // For handover, the network agent is transferred to the other data connection. if (mDisconnectParams == null || !mDisconnectParams.mIsHandover) { mNetworkAgent.sendNetworkInfo(mNetworkInfo); } mNetworkAgent = null; } } Loading Loading @@ -2183,7 +2270,8 @@ public class DataConnection extends StateMachine { new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration); log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext); Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg); DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), false, msg); DataConnection.this.sendMessage(DataConnection.this. obtainMessage(EVENT_DISCONNECT, dp)); } Loading Loading @@ -2365,30 +2453,33 @@ public class DataConnection extends StateMachine { * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). * @param connectionGeneration used to track a single connection request so disconnects can get * ignored if obsolete. * @param isHandover {@code true} if this request is for handover. */ public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { Message onCompletedMsg, int connectionGeneration, boolean isHandover) { if (DBG) { log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_CONNECT, new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, connectionGeneration)); connectionGeneration, isHandover)); } /** * Tear down the connection through the apn on the network. * * @param apnContext APN context * @param reason reason to tear down * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj. */ public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) { if (DBG) { log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg); log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_DISCONNECT, new DisconnectParams(apnContext, reason, onCompletedMsg)); new DisconnectParams(apnContext, reason, false, onCompletedMsg)); } // ******* "public" interface Loading @@ -2405,13 +2496,14 @@ public class DataConnection extends StateMachine { * Tear down the connection through the apn on the network. Ignores reference count and * and always tears down. * * @param isHandover {@code true} if this is for handover * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj. */ public void tearDownAll(String reason, Message onCompletedMsg) { public void tearDownAll(String reason, boolean isHandover, Message onCompletedMsg) { if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg); sendMessage(DataConnection.EVENT_DISCONNECT_ALL, new DisconnectParams(null, reason, onCompletedMsg)); new DisconnectParams(null, reason, isHandover, onCompletedMsg)); } /** Loading Loading @@ -2479,6 +2571,10 @@ public class DataConnection extends StateMachine { return new ArrayList<>(mApnContexts.keySet()); } public DcNetworkAgent getNetworkAgent() { return mNetworkAgent; } /** * @return the string for msg.what as our info. */ Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +180 −100 File changed.Preview size limit exceeded, changes collapsed. Show changes src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java +7 −3 Original line number Diff line number Diff line Loading @@ -159,15 +159,19 @@ public class TelephonyNetworkFactory extends NetworkFactory { private void requestNetworkInternal(NetworkRequest networkRequest) { int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (mPhone.getDcTracker(transportType) != null) { mPhone.getDcTracker(transportType).requestNetwork(networkRequest, mLocalLog); // TODO: Handover logic will be added later. For now always normal request. mPhone.getDcTracker(transportType).requestNetwork(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, mLocalLog); } } private void releaseNetworkInternal(NetworkRequest networkRequest, boolean cleanUpOnRelease) { int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (mPhone.getDcTracker(transportType) != null) { mPhone.getDcTracker(transportType).releaseNetwork(networkRequest, mLocalLog, cleanUpOnRelease); // TODO: Handover logic will be added later. For now always normal or detach request. mPhone.getDcTracker(transportType).releaseNetwork(networkRequest, cleanUpOnRelease ? DcTracker.RELEASE_TYPE_DETACH : DcTracker.RELEASE_TYPE_NORMAL, mLocalLog); } } Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +85 −10 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkRequest; import android.telephony.data.ApnSetting; Loading Loading @@ -114,19 +116,92 @@ public class ApnContextTest extends TelephonyTest { @Test @SmallTest public void testNetworkRequest() throws Exception { public void testNetworkRequestNormal() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr, log); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT)); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); // The same request should be ignore. verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); NetworkRequest nr2 = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .build(); LocalLog log2 = new LocalLog(3); mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2); verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL, log); verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); } @Test @SmallTest public void testNetworkRequestDetach() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); // The same request should be ignore. verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); NetworkRequest nr2 = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .build(); LocalLog log2 = new LocalLog(3); mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2); verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_DETACH)); mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); } @Test @SmallTest public void testNetworkRequestHandover() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_HANDOVER)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_HANDOVER)); } @Test Loading Loading
src/java/com/android/internal/telephony/dataconnection/ApnContext.java +11 −12 Original line number Diff line number Diff line Loading @@ -32,12 +32,13 @@ import com.android.internal.R; import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -412,19 +413,21 @@ public class ApnContext { } } public void requestNetwork(NetworkRequest networkRequest, LocalLog log) { public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) { log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size()); } else { mLocalLogs.add(log); mNetworkRequests.add(networkRequest); mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType)); mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); } } } public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log) == false) { log.log("ApnContext.releaseNetwork can't find this log"); Loading @@ -438,19 +441,15 @@ public class ApnContext { mNetworkRequests.remove(networkRequest); log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() + " requests."); if (mNetworkRequests.size() == 0) { mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType)); if (mNetworkRequests.size() == 0 || type == DcTracker.RELEASE_TYPE_DETACH || type == DcTracker.RELEASE_TYPE_HANDOVER) { mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); } } } } public List<NetworkRequest> getNetworkRequests() { synchronized (mRefCountLock) { return new ArrayList<NetworkRequest>(mNetworkRequests); } } /** * @param excludeDun True if excluding requests that have DUN capability * @return True if the attached network requests contain restricted capability. Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +145 −49 Original line number Diff line number Diff line Loading @@ -129,14 +129,16 @@ public class DataConnection extends StateMachine { int mRilRat; Message mOnCompletedMsg; final int mConnectionGeneration; final boolean mIsHandover; ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { Message onCompletedMsg, int connectionGeneration, boolean isHandover) { mApnContext = apnContext; mProfileId = profileId; mRilRat = rilRadioTechnology; mOnCompletedMsg = onCompletedMsg; mConnectionGeneration = connectionGeneration; mIsHandover = isHandover; } @Override Loading @@ -144,7 +146,9 @@ public class DataConnection extends StateMachine { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mProfileId=" + mProfileId + " mRat=" + mRilRat + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + " mIsHandover=" + mIsHandover + "}"; } } Loading @@ -155,11 +159,14 @@ public class DataConnection extends StateMachine { int mTag; public ApnContext mApnContext; String mReason; final boolean mIsHandover; Message mOnCompletedMsg; DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) { DisconnectParams(ApnContext apnContext, String reason, boolean isHandover, Message onCompletedMsg) { mApnContext = apnContext; mReason = reason; mIsHandover = isHandover; mOnCompletedMsg = onCompletedMsg; } Loading @@ -167,6 +174,7 @@ public class DataConnection extends StateMachine { public String toString() { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mReason=" + mReason + " mIsHandover=" + mIsHandover + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; } } Loading Loading @@ -286,9 +294,12 @@ public class DataConnection extends StateMachine { DataServiceManager dataServiceManager, DcTesterFailBringUpAll failBringUpAll, DcController dcc) { String transportType = (dataServiceManager.getTransportType() == TransportType.WWAN) ? "C" // Cellular : "I"; // IWLAN DataConnection dc = new DataConnection(phone, "DC-" + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, dcc); "DC-" + transportType + "-" + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, dcc); dc.start(); if (DBG) dc.log("Made " + dc.getName()); return dc; Loading Loading @@ -498,21 +509,35 @@ public class DataConnection extends StateMachine { setInitialState(mInactiveState); } /** * Get the DcTracker for handover. There are multiple DcTrackers for different transports (e.g. * WWAN, WLAN). For data handover, we need to handover the existing data connection from current * DcTracker to the DcTracker on another transport. */ private DcTracker getHandoverDcTracker() { int transportType = mDataServiceManager.getTransportType(); // Get the DcTracker from the other transport. return mPhone.getDcTracker(transportType == TransportType.WWAN ? TransportType.WLAN : TransportType.WWAN); } /** * Begin setting up a data connection, calls setupDataCall * and the ConnectionParams will be returned with the * EVENT_SETUP_DATA_CONNECTION_DONE * * @param cp is the connection parameters * * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success. */ private void onConnect(ConnectionParams cp) { private @DataFailCause.FailCause int connect(ConnectionParams cp) { if (DBG) { log("onConnect: carrier='" + mApnSetting.getEntryName() log("connect: carrier='" + mApnSetting.getEntryName() + "' APN='" + mApnSetting.getApnName() + "' proxy='" + mApnSetting.getProxyAddressAsString() + "' port='" + mApnSetting.getProxyPort() + "'"); } if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.onConnect"); if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.connect"); // Check if we should fake an error. if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { Loading @@ -525,11 +550,11 @@ public class DataConnection extends StateMachine { AsyncResult.forMessage(msg, response, null); sendMessage(msg); if (DBG) { log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() + " send error response=" + response); } mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; return; return DataFailCause.NONE; } mCreateTime = -1; Loading @@ -553,11 +578,46 @@ public class DataConnection extends StateMachine { boolean allowRoaming = mPhone.getDataRoamingEnabled() || (isModemRoaming && !mPhone.getServiceState().getDataRoaming()); // Check if this data setup is a handover. LinkProperties linkProperties = null; int reason = DataService.REQUEST_REASON_NORMAL; if (cp.mIsHandover) { // If this is a data setup for handover, we need to pass the link properties // of the existing data connection to the modem. DcTracker dcTracker = getHandoverDcTracker(); if (dcTracker == null || cp.mApnContext == null) { loge("connect: Handover failed. dcTracker=" + dcTracker + ", apnContext=" + cp.mApnContext); return DataFailCause.HANDOVER_FAILED; } DataConnection dc = dcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType()); if (dc == null) { loge("connect: Can't find data connection for handover."); return DataFailCause.HANDOVER_FAILED; } linkProperties = dc.getLinkProperties(); if (linkProperties == null) { loge("connect: Can't find link properties of handover data connection. dc=" + dc); return DataFailCause.HANDOVER_FAILED; } reason = DataService.REQUEST_REASON_HANDOVER; } mDataServiceManager.setupDataCall( ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), dp, isModemRoaming, allowRoaming, DataService.REQUEST_REASON_NORMAL, null, msg); ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), dp, isModemRoaming, allowRoaming, reason, linkProperties, msg); TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, dp.getProfileId(), dp.getApn(), dp.getProtocol()); return DataFailCause.NONE; } public void onSubscriptionOverride(int overrideMask, int overrideValue) { Loading @@ -581,6 +641,8 @@ public class DataConnection extends StateMachine { if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF) || TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { discReason = DataService.REQUEST_REASON_SHUTDOWN; } else if (dp.mIsHandover) { discReason = DataService.REQUEST_REASON_HANDOVER; } } Loading @@ -599,7 +661,7 @@ public class DataConnection extends StateMachine { if (apnContext == alreadySent) continue; if (reason != null) apnContext.setReason(reason); Pair<ApnContext, Integer> pair = new Pair<>(apnContext, cp.mConnectionGeneration); Message msg = mDct.obtainMessage(event, pair); Message msg = mDct.obtainMessage(event, mCid, cp.mIsHandover ? 1 : 0, pair); AsyncResult.forMessage(msg); msg.sendToTarget(); } Loading @@ -624,6 +686,7 @@ public class DataConnection extends StateMachine { long timeStamp = System.currentTimeMillis(); connectionCompletedMsg.arg1 = mCid; connectionCompletedMsg.arg2 = cp.mIsHandover ? 1 : 0; if (cause == DataFailCause.NONE) { mCreateTime = timeStamp; Loading Loading @@ -746,6 +809,7 @@ public class DataConnection extends StateMachine { ConnectionParams cp) { SetupResult result; log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response); if (cp.mTag != mTag) { if (DBG) { log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); Loading Loading @@ -1512,8 +1576,6 @@ public class DataConnection extends StateMachine { @Override public boolean processMessage(Message msg) { boolean retVal; switch (msg.what) { case EVENT_RESET: case EVENT_REEVALUATE_RESTRICTED_STATE: Loading @@ -1521,45 +1583,43 @@ public class DataConnection extends StateMachine { log("DcInactiveState: msg.what=" + getWhatToString(msg.what) + ", ignore we're already done"); } retVal = HANDLED; break; return HANDLED; case EVENT_CONNECT: if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); ConnectionParams cp = (ConnectionParams) msg.obj; if (initConnection(cp)) { onConnect(mConnectionParams); transitionTo(mActivatingState); } else { if (DBG) { if (!initConnection(cp)) { log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); } notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, false); transitionTo(mInactiveState); return HANDLED; } retVal = HANDLED; break; int cause = connect(cp); if (cause != DataFailCause.NONE) { log("DcInactiveState: msg.what=EVENT_CONNECT connect failed"); notifyConnectCompleted(cp, cause, false); transitionTo(mInactiveState); return HANDLED; } transitionTo(mActivatingState); return HANDLED; case EVENT_DISCONNECT: if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); notifyDisconnectCompleted((DisconnectParams)msg.obj, false); retVal = HANDLED; break; return HANDLED; case EVENT_DISCONNECT_ALL: if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); notifyDisconnectCompleted((DisconnectParams)msg.obj, false); retVal = HANDLED; break; return HANDLED; default: if (VDBG) { log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what)); } retVal = NOT_HANDLED; break; return NOT_HANDLED; } return retVal; } } private DcInactiveState mInactiveState = new DcInactiveState(); Loading Loading @@ -1728,9 +1788,30 @@ public class DataConnection extends StateMachine { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); } if (mConnectionParams != null && mConnectionParams.mIsHandover) { // If this is a data setup for handover, we need to reuse the existing network agent // instead of creating a new one. This should be transparent to connectivity // service. DcTracker dcTracker = getHandoverDcTracker(); DataConnection dc = dcTracker.getDataConnectionByApnType( mConnectionParams.mApnContext.getApnType()); if (dc != null) { mNetworkAgent = dc.getNetworkAgent(); if (mNetworkAgent != null) { mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); mNetworkAgent.sendLinkProperties(mLinkProperties); } else { loge("Failed to get network agent from original data connection " + dc); } } else { loge("Cannot find the data connection for handover."); } } else { mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties, 50, misc); } if (mDataServiceManager.getTransportType() == TransportType.WWAN) { mPhone.mCi.registerForNattKeepaliveStatus( getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null); Loading Loading @@ -1761,7 +1842,13 @@ public class DataConnection extends StateMachine { mPhone.mCi.unregisterForLceInfo(getHandler()); } if (mNetworkAgent != null) { // We do not want to update the network info if this is a handover. For all other // cases we need to update connectivity service with the latest network info. // // For handover, the network agent is transferred to the other data connection. if (mDisconnectParams == null || !mDisconnectParams.mIsHandover) { mNetworkAgent.sendNetworkInfo(mNetworkInfo); } mNetworkAgent = null; } } Loading Loading @@ -2183,7 +2270,8 @@ public class DataConnection extends StateMachine { new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration); log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext); Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg); DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), false, msg); DataConnection.this.sendMessage(DataConnection.this. obtainMessage(EVENT_DISCONNECT, dp)); } Loading Loading @@ -2365,30 +2453,33 @@ public class DataConnection extends StateMachine { * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). * @param connectionGeneration used to track a single connection request so disconnects can get * ignored if obsolete. * @param isHandover {@code true} if this request is for handover. */ public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { Message onCompletedMsg, int connectionGeneration, boolean isHandover) { if (DBG) { log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_CONNECT, new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, connectionGeneration)); connectionGeneration, isHandover)); } /** * Tear down the connection through the apn on the network. * * @param apnContext APN context * @param reason reason to tear down * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj. */ public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) { if (DBG) { log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg); log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_DISCONNECT, new DisconnectParams(apnContext, reason, onCompletedMsg)); new DisconnectParams(apnContext, reason, false, onCompletedMsg)); } // ******* "public" interface Loading @@ -2405,13 +2496,14 @@ public class DataConnection extends StateMachine { * Tear down the connection through the apn on the network. Ignores reference count and * and always tears down. * * @param isHandover {@code true} if this is for handover * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj. */ public void tearDownAll(String reason, Message onCompletedMsg) { public void tearDownAll(String reason, boolean isHandover, Message onCompletedMsg) { if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg); sendMessage(DataConnection.EVENT_DISCONNECT_ALL, new DisconnectParams(null, reason, onCompletedMsg)); new DisconnectParams(null, reason, isHandover, onCompletedMsg)); } /** Loading Loading @@ -2479,6 +2571,10 @@ public class DataConnection extends StateMachine { return new ArrayList<>(mApnContexts.keySet()); } public DcNetworkAgent getNetworkAgent() { return mNetworkAgent; } /** * @return the string for msg.what as our info. */ Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +180 −100 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java +7 −3 Original line number Diff line number Diff line Loading @@ -159,15 +159,19 @@ public class TelephonyNetworkFactory extends NetworkFactory { private void requestNetworkInternal(NetworkRequest networkRequest) { int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (mPhone.getDcTracker(transportType) != null) { mPhone.getDcTracker(transportType).requestNetwork(networkRequest, mLocalLog); // TODO: Handover logic will be added later. For now always normal request. mPhone.getDcTracker(transportType).requestNetwork(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, mLocalLog); } } private void releaseNetworkInternal(NetworkRequest networkRequest, boolean cleanUpOnRelease) { int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (mPhone.getDcTracker(transportType) != null) { mPhone.getDcTracker(transportType).releaseNetwork(networkRequest, mLocalLog, cleanUpOnRelease); // TODO: Handover logic will be added later. For now always normal or detach request. mPhone.getDcTracker(transportType).releaseNetwork(networkRequest, cleanUpOnRelease ? DcTracker.RELEASE_TYPE_DETACH : DcTracker.RELEASE_TYPE_NORMAL, mLocalLog); } } Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +85 −10 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkRequest; import android.telephony.data.ApnSetting; Loading Loading @@ -114,19 +116,92 @@ public class ApnContextTest extends TelephonyTest { @Test @SmallTest public void testNetworkRequest() throws Exception { public void testNetworkRequestNormal() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr, log); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT)); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); // The same request should be ignore. verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); NetworkRequest nr2 = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .build(); LocalLog log2 = new LocalLog(3); mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2); verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL, log); verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); } @Test @SmallTest public void testNetworkRequestDetach() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log); // The same request should be ignore. verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); NetworkRequest nr2 = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .build(); LocalLog log2 = new LocalLog(3); mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2); verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_NORMAL)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_DETACH)); mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_NORMAL)); } @Test @SmallTest public void testNetworkRequestHandover() throws Exception { LocalLog log = new LocalLog(3); NetworkRequest nr1 = new NetworkRequest.Builder().build(); mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, log); verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.REQUEST_TYPE_HANDOVER)); mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER, log); verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), eq(DcTracker.RELEASE_TYPE_HANDOVER)); } @Test Loading