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
This commit is contained in:
lucaslin
2019-11-22 12:46:32 +08:00
parent 732d7f96f3
commit 784ca66669
2 changed files with 56 additions and 5 deletions

View File

@@ -18,6 +18,7 @@ package com.android.server.connectivity;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Notification; import android.app.Notification;
@@ -89,14 +90,22 @@ public class NetworkNotificationManager {
mNotificationTypeMap = new SparseIntArray(); 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. // TODO: deal more gracefully with multi-transport networks.
private static int getFirstTransportType(NetworkAgentInfo nai) { 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++) { for (int i = 0; i < 64; i++) {
if (nai.networkCapabilities.hasTransport(i)) return i; if (nai.networkCapabilities.hasTransport(i)) return i;
} }
return -1; return -1;
} }
// TODO: Remove @TransportType or change it to @Transport.
private static String getTransportName(@TransportType int transportType) { private static String getTransportName(@TransportType int transportType) {
Resources r = Resources.getSystem(); Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name); String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
@@ -146,7 +155,7 @@ public class NetworkNotificationManager {
final int transportType; final int transportType;
final String name; final String name;
if (nai != null) { if (nai != null) {
transportType = getFirstTransportType(nai); transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo(); final String extraInfo = nai.networkInfo.getExtraInfo();
name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo; name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks. // Only notify for Internet-capable networks.
@@ -175,7 +184,7 @@ public class NetworkNotificationManager {
tag, nameOf(eventId), getTransportName(transportType), name, highPriority)); tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
} }
Resources r = Resources.getSystem(); Resources r = mContext.getResources();
final CharSequence title; final CharSequence title;
final CharSequence details; final CharSequence details;
int icon = getIcon(transportType, notifyType); int icon = getIcon(transportType, notifyType);
@@ -239,7 +248,7 @@ public class NetworkNotificationManager {
details = r.getString(R.string.captive_portal_logged_in_detailed); details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) { } else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType); String fromTransport = getTransportName(transportType);
String toTransport = getTransportName(getFirstTransportType(switchToNai)); String toTransport = getTransportName(approximateTransportType(switchToNai));
title = r.getString(R.string.network_switch_metered, toTransport); title = r.getString(R.string.network_switch_metered, toTransport);
details = r.getString(R.string.network_switch_metered_detail, toTransport, details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport); fromTransport);
@@ -340,8 +349,8 @@ public class NetworkNotificationManager {
} }
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) { public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
String fromTransport = getTransportName(getFirstTransportType(fromNai)); String fromTransport = getTransportName(approximateTransportType(fromNai));
String toTransport = getTransportName(getFirstTransportType(toNai)); String toTransport = getTransportName(approximateTransportType(toNai));
String text = mContext.getResources().getString( String text = mContext.getResources().getString(
R.string.network_switch_metered_toast, fromTransport, toTransport); R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();

View File

@@ -20,6 +20,7 @@ import static com.android.server.connectivity.NetworkNotificationManager.Notific
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
@@ -40,6 +41,7 @@ import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import org.junit.Before; import org.junit.Before;
@@ -60,12 +62,19 @@ public class NetworkNotificationManagerTest {
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities(); static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities(); static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
static { static {
CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 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; @Mock Context mCtx;
@@ -75,6 +84,7 @@ public class NetworkNotificationManagerTest {
@Mock NotificationManager mNotificationManager; @Mock NotificationManager mNotificationManager;
@Mock NetworkAgentInfo mWifiNai; @Mock NetworkAgentInfo mWifiNai;
@Mock NetworkAgentInfo mCellNai; @Mock NetworkAgentInfo mCellNai;
@Mock NetworkAgentInfo mVpnNai;
@Mock NetworkInfo mNetworkInfo; @Mock NetworkInfo mNetworkInfo;
ArgumentCaptor<Notification> mCaptor; ArgumentCaptor<Notification> mCaptor;
@@ -88,6 +98,9 @@ public class NetworkNotificationManagerTest {
mWifiNai.networkInfo = mNetworkInfo; mWifiNai.networkInfo = mNetworkInfo;
mCellNai.networkCapabilities = CELL_CAPABILITIES; mCellNai.networkCapabilities = CELL_CAPABILITIES;
mCellNai.networkInfo = mNetworkInfo; mCellNai.networkInfo = mNetworkInfo;
mVpnNai.networkCapabilities = VPN_CAPABILITIES;
mVpnNai.networkInfo = mNetworkInfo;
doReturn(true).when(mVpnNai).isVPN();
when(mCtx.getResources()).thenReturn(mResources); when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm); when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo()); when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -97,6 +110,35 @@ public class NetworkNotificationManagerTest {
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager); 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 @Test
public void testNotificationsShownAndCleared() { public void testNotificationsShownAndCleared() {
final int NETWORK_ID_BASE = 100; final int NETWORK_ID_BASE = 100;