Fix title of PRIVATE_DNS_BROKEN notification when connecting VPN
NetworkNotificationManager will only get the first transport
type from the NetworkCapabilities of network, and if the device
connects to a VPN and its underlying network is wifi, then the
first finding transport type will be TRANSPORT_WIFI. So, if the
private DNS is broken when device connected to VPN,
NetworkNotificationManager will try to get the SSID for the
title of notification but failed. For this kind of case, the
title of PRIVATE_DNS_BROKEN notification will show
"null has no internet access".
Bug: 143340533
Test: 1. Build pass.
2. Connect to VPN and let private DNS to be broken, check
title of PRIVATE_DNS_BROKEN notification.
3. atest FrameworksNetTests
Change-Id: I1ed018cc8774d4fce4b94854f8e8703a28818463
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index d13e675..bc83780 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Notification;
@@ -89,14 +90,22 @@
mNotificationTypeMap = new SparseIntArray();
}
+ @VisibleForTesting
+ protected static int approximateTransportType(NetworkAgentInfo nai) {
+ return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
+ }
+
// TODO: deal more gracefully with multi-transport networks.
private static int getFirstTransportType(NetworkAgentInfo nai) {
+ // TODO: The range is wrong, the safer and correct way is to change the range from
+ // MIN_TRANSPORT to MAX_TRANSPORT.
for (int i = 0; i < 64; i++) {
if (nai.networkCapabilities.hasTransport(i)) return i;
}
return -1;
}
+ // TODO: Remove @TransportType or change it to @Transport.
private static String getTransportName(@TransportType int transportType) {
Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
@@ -146,7 +155,7 @@
final int transportType;
final String name;
if (nai != null) {
- transportType = getFirstTransportType(nai);
+ transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks.
@@ -175,7 +184,7 @@
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
- Resources r = Resources.getSystem();
+ Resources r = mContext.getResources();
final CharSequence title;
final CharSequence details;
int icon = getIcon(transportType, notifyType);
@@ -239,7 +248,7 @@
details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType);
- String toTransport = getTransportName(getFirstTransportType(switchToNai));
+ String toTransport = getTransportName(approximateTransportType(switchToNai));
title = r.getString(R.string.network_switch_metered, toTransport);
details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport);
@@ -340,8 +349,8 @@
}
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- String fromTransport = getTransportName(getFirstTransportType(fromNai));
- String toTransport = getTransportName(getFirstTransportType(toNai));
+ String fromTransport = getTransportName(approximateTransportType(fromNai));
+ String toTransport = getTransportName(approximateTransportType(toNai));
String text = mContext.getResources().getString(
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 9580763..d57f225 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import org.junit.Before;
@@ -60,12 +62,19 @@
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
+ static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
static {
CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+ // Set the underyling network to wifi.
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
+ VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
}
@Mock Context mCtx;
@@ -75,6 +84,7 @@
@Mock NotificationManager mNotificationManager;
@Mock NetworkAgentInfo mWifiNai;
@Mock NetworkAgentInfo mCellNai;
+ @Mock NetworkAgentInfo mVpnNai;
@Mock NetworkInfo mNetworkInfo;
ArgumentCaptor<Notification> mCaptor;
@@ -88,6 +98,9 @@
mWifiNai.networkInfo = mNetworkInfo;
mCellNai.networkCapabilities = CELL_CAPABILITIES;
mCellNai.networkInfo = mNetworkInfo;
+ mVpnNai.networkCapabilities = VPN_CAPABILITIES;
+ mVpnNai.networkInfo = mNetworkInfo;
+ doReturn(true).when(mVpnNai).isVPN();
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -97,6 +110,35 @@
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
}
+ private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
+ final String tag = NetworkNotificationManager.tagFor(id);
+ mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
+ final int transportType = NetworkNotificationManager.approximateTransportType(nai);
+ if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
+ verify(mResources, times(1)).getString(title, eq(any()));
+ } else {
+ verify(mResources, times(1)).getString(title);
+ }
+ verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+ }
+
+ @Test
+ public void testTitleOfPrivateDnsBroken() {
+ // Test the title of mobile data.
+ verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
+ reset(mResources);
+
+ // Test the title of wifi.
+ verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
+ reset(mResources);
+
+ // Test the title of other networks.
+ verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
+ reset(mResources);
+ }
+
@Test
public void testNotificationsShownAndCleared() {
final int NETWORK_ID_BASE = 100;