Merge "Added network agent auto clean up logic"
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
index 796ae94..ba04a3b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
@@ -29,6 +29,7 @@
import android.net.QosSessionAttributes;
import android.net.SocketKeepalive;
import android.net.Uri;
+import android.os.Handler;
import android.os.Message;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.TransportType;
@@ -41,6 +42,7 @@
import android.util.LocalLog;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
@@ -82,6 +84,8 @@
private final Phone mPhone;
+ private final Handler mHandler;
+
private int mTransportType;
private NetworkCapabilities mNetworkCapabilities;
@@ -102,7 +106,10 @@
private static final long NETWORK_UNWANTED_ANOMALY_WINDOW_MS = TimeUnit.MINUTES.toMillis(5);
private static final int NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES = 12;
- DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config,
+ private static final int EVENT_UNWANTED_TIMEOUT = 1;
+
+ @VisibleForTesting
+ public DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config,
NetworkProvider networkProvider, int transportType) {
super(phone.getContext(), dc.getHandler().getLooper(), "DcNetworkAgent",
dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config,
@@ -111,6 +118,18 @@
mId = getNetwork().getNetId();
mTag = "DcNetworkAgent" + "-" + mId;
mPhone = phone;
+ mHandler = new Handler(dc.getHandler().getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == EVENT_UNWANTED_TIMEOUT) {
+ loge("onNetworkUnwanted timed out. Perform silent de-register.");
+ logd("Unregister from connectivity service. " + sInterfaceNames.get(mId)
+ + " removed.");
+ sInterfaceNames.remove(mId);
+ DcNetworkAgent.this.unregister();
+ }
+ }
+ };
mNetworkCapabilities = dc.getNetworkCapabilities();
mTransportType = transportType;
mDataConnection = dc;
@@ -203,6 +222,7 @@
@Override
public synchronized void onNetworkUnwanted() {
+ mHandler.sendEmptyMessageDelayed(EVENT_UNWANTED_TIMEOUT, TimeUnit.SECONDS.toMillis(30));
trackNetworkUnwanted();
if (mDataConnection == null) {
loge("onNetworkUnwanted found called on no-owner DcNetworkAgent!");
@@ -356,6 +376,7 @@
public synchronized void unregister(DataConnection dc) {
if (!isOwned(dc, "unregister")) return;
+ mHandler.removeMessages(EVENT_UNWANTED_TIMEOUT);
logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed.");
sInterfaceNames.remove(mId);
super.unregister();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java
new file mode 100644
index 0000000..78438e4
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkInfo;
+import android.net.NetworkProvider;
+import android.os.Looper;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class DcNetworkAgentTest extends TelephonyTest {
+
+ private DcNetworkAgent mDcNetworkAgent;
+ private DataConnection mDc;
+ private DcController mDcc;
+ private DcFailBringUp mDcFailBringUp;
+
+ private DataServiceManager mDataServiceManager;
+ private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
+ private NetworkProvider mNetworkProvider;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ logd("+Setup!");
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ doReturn(false).when(mPhone).isUsingNewDataStack();
+ mDataServiceManager = Mockito.mock(DataServiceManager.class);
+ mDcTesterFailBringUpAll = Mockito.mock(DcTesterFailBringUpAll.class);
+ mNetworkProvider = Mockito.mock(NetworkProvider.class);
+
+ final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder();
+ configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE);
+ configBuilder.setLegacyTypeName("MOBILE");
+ configBuilder.setLegacySubType(TelephonyManager.NETWORK_TYPE_LTE);
+ configBuilder.setLegacySubTypeName("LTE");
+ configBuilder.setLegacyExtraInfo("apn");
+
+ doReturn("fake.action_detached").when(mPhone).getActionDetached();
+ mDcFailBringUp = new DcFailBringUp();
+ mDcFailBringUp.saveParameters(0, 0, -2);
+ doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
+
+ mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(),
+ "");
+ mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager,
+ mDcTesterFailBringUpAll, mDcc);
+
+ LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName("fake_iface");
+ Field field = DataConnection.class.getDeclaredField("mLinkProperties");
+ field.setAccessible(true);
+ field.set(mDc, linkProperties);
+
+ mDcNetworkAgent = new DcNetworkAgent(mDc, mPhone, 45, configBuilder.build(),
+ mNetworkProvider, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ logd("-Setup!");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private void verifyDisconnected() throws Exception {
+ Field field = NetworkAgent.class.getDeclaredField("mNetworkInfo");
+ field.setAccessible(true);
+ NetworkInfo networkInfo = (NetworkInfo) field.get(mDcNetworkAgent);
+ assertEquals(NetworkInfo.DetailedState.DISCONNECTED, networkInfo.getDetailedState());
+ }
+
+ @Test
+ public void testUnwantedTimeout() throws Exception {
+ mDcNetworkAgent.markConnected();
+ mDcNetworkAgent.onNetworkUnwanted();
+ processAllFutureMessages();
+ verifyDisconnected();
+ }
+}