Replace NotificationManager @hide APIs

Connectivity service module is using some NotificationManager
@hide APIs but they are not able to call after CS become a
mainline module. Thus, replace them with similar System APIs.

Bug: 170593746
Test: atest FrameworksNetTests
Change-Id: I2644867cfc01d8d651c7029134294a9d44fdb471
This commit is contained in:
paulhu
2020-10-07 19:03:42 +08:00
parent c04c6aaf58
commit 117bde44fa
5 changed files with 55 additions and 44 deletions

View File

@@ -1147,7 +1147,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler); mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager, mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
mContext.getSystemService(NotificationManager.class)); // Pass a NotificationManager obtained from a context with UserHandle.ALL, then
// NetworkNotificationManager can put up a notification to all users.
// TODO: Create NotificationManager in NetworkNotificationManager directly.
(NotificationManager) mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */)
.getSystemService(Context.NOTIFICATION_SERVICE));
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(), final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,

View File

@@ -30,7 +30,6 @@ import android.content.res.Resources;
import android.net.NetworkSpecifier; import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier; import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
@@ -75,8 +74,11 @@ public class NetworkNotificationManager {
private static final boolean DBG = true; private static final boolean DBG = true;
private static final boolean VDBG = false; private static final boolean VDBG = false;
// The context is for the current user (system server)
private final Context mContext; private final Context mContext;
private final TelephonyManager mTelephonyManager; private final TelephonyManager mTelephonyManager;
// The notification manager is created from a context for User.ALL, so notifications
// will be sent to all users.
private final NotificationManager mNotificationManager; private final NotificationManager mNotificationManager;
// Tracks the types of notifications managed by this instance, from creation to cancellation. // Tracks the types of notifications managed by this instance, from creation to cancellation.
private final SparseIntArray mNotificationTypeMap; private final SparseIntArray mNotificationTypeMap;
@@ -282,7 +284,7 @@ public class NetworkNotificationManager {
mNotificationTypeMap.put(id, eventId); mNotificationTypeMap.put(id, eventId);
try { try {
mNotificationManager.notifyAsUser(tag, eventId, notification, UserHandle.ALL); mNotificationManager.notify(tag, eventId, notification);
} catch (NullPointerException npe) { } catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe); Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
} }
@@ -311,7 +313,7 @@ public class NetworkNotificationManager {
nameOf(eventId))); nameOf(eventId)));
} }
try { try {
mNotificationManager.cancelAsUser(tag, eventId, UserHandle.ALL); mNotificationManager.cancel(tag, eventId);
} catch (NullPointerException npe) { } catch (NullPointerException npe) {
Slog.d(TAG, String.format( Slog.d(TAG, String.format(
"failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe); "failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);

View File

@@ -251,6 +251,7 @@ import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
@@ -451,6 +452,13 @@ public class ConnectivityServiceTest {
return super.getSystemService(name); return super.getSystemService(name);
} }
@Override
public Context createContextAsUser(UserHandle user, int flags) {
final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
doReturn(user).when(asUser).getUser();
return asUser;
}
@Override @Override
public ContentResolver getContentResolver() { public ContentResolver getContentResolver() {
return mContentResolver; return mContentResolver;
@@ -4992,22 +5000,22 @@ public class ConnectivityServiceTest {
// simulate that situation and check if ConnectivityService could filter that case. // simulate that situation and check if ConnectivityService could filter that case.
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle(); waitForIdle();
verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notifyAsUser(anyString(), verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notify(anyString(),
eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL)); eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
// If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
// shown. // shown.
mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */); mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle(); waitForIdle();
verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancelAsUser(anyString(), verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancel(anyString(),
eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), eq(UserHandle.ALL)); eq(NotificationType.PRIVATE_DNS_BROKEN.eventId));
// If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
// shown again. // shown again.
mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */); mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle(); waitForIdle();
verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notifyAsUser(anyString(), verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notify(anyString(),
eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL)); eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
} }
@Test @Test

View File

@@ -114,7 +114,7 @@ public class NetworkNotificationManagerTest {
final String tag = NetworkNotificationManager.tagFor(id); final String tag = NetworkNotificationManager.tagFor(id);
mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true); mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1))
.notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any()); .notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
final int transportType = NetworkNotificationManager.approximateTransportType(nai); final int transportType = NetworkNotificationManager.approximateTransportType(nai);
if (transportType == NetworkCapabilities.TRANSPORT_WIFI) { if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
verify(mResources, times(1)).getString(title, eq(any())); verify(mResources, times(1)).getString(title, eq(any()));
@@ -164,8 +164,8 @@ public class NetworkNotificationManagerTest {
final int id = ids.get(i); final int id = ids.get(i);
final int eventId = types.get(i).eventId; final int eventId = types.get(i).eventId;
final String tag = NetworkNotificationManager.tagFor(id); final String tag = NetworkNotificationManager.tagFor(id);
verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any()); verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any()); verify(mNotificationManager, times(1)).cancel(eq(tag), eq(eventId));
} }
} }
@@ -174,13 +174,13 @@ public class NetworkNotificationManagerTest {
mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false); mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false); mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); verify(mNotificationManager, never()).notify(any(), anyInt(), any());
mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false); mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
final int eventId = NO_INTERNET.eventId; final int eventId = NO_INTERNET.eventId;
final String tag = NetworkNotificationManager.tagFor(102); final String tag = NetworkNotificationManager.tagFor(102);
verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any()); verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
} }
@Test @Test
@@ -191,7 +191,7 @@ public class NetworkNotificationManagerTest {
mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false); mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false); mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); verify(mNotificationManager, never()).notify(any(), anyInt(), any());
} }
@Test @Test
@@ -201,19 +201,16 @@ public class NetworkNotificationManagerTest {
// Show first NO_INTERNET // Show first NO_INTERNET
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false); mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
.notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false); mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
.cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any()); verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
verify(mNotificationManager, times(1))
.notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
// Network disconnects // Network disconnects
mManager.clearNotification(id); mManager.clearNotification(id);
verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any()); verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
} }
@Test @Test
@@ -223,18 +220,17 @@ public class NetworkNotificationManagerTest {
// Show first SIGN_IN // Show first SIGN_IN
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false); mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
.notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
reset(mNotificationManager); reset(mNotificationManager);
// NO_INTERNET arrives after, but is ignored. // NO_INTERNET arrives after, but is ignored.
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false); mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any()); verify(mNotificationManager, never()).cancel(any(), anyInt());
verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); verify(mNotificationManager, never()).notify(any(), anyInt(), any());
// Network disconnects // Network disconnects
mManager.clearNotification(id); mManager.clearNotification(id);
verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any()); verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
} }
@Test @Test
@@ -246,24 +242,20 @@ public class NetworkNotificationManagerTest {
// to previous type or not. If they are equal then clear the notification; if they are not // to previous type or not. If they are equal then clear the notification; if they are not
// equal then return. // equal then return.
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false); mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
.notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
// Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
// should be cleared. // should be cleared.
mManager.clearNotification(id, NO_INTERNET); mManager.clearNotification(id, NO_INTERNET);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
.cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
// SIGN_IN is popped-up. // SIGN_IN is popped-up.
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false); mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)) verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
.notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
// The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
// cleared. // cleared.
mManager.clearNotification(id, PARTIAL_CONNECTIVITY); mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
verify(mNotificationManager, never()) verify(mNotificationManager, never()).cancel(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId));
.cancelAsUser(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId), any());
} }
} }

View File

@@ -45,6 +45,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -106,6 +107,7 @@ import com.android.server.IpSecService;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
import org.mockito.Answers; import org.mockito.Answers;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
@@ -215,6 +217,8 @@ public class VpnTest {
when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG); when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager); when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
when(mContext.getSystemServiceName(NotificationManager.class))
.thenReturn(Context.NOTIFICATION_SERVICE);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager); .thenReturn(mNotificationManager);
when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))) when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
@@ -594,26 +598,23 @@ public class VpnTest {
// Don't show a notification for regular disconnected states. // Don't show a notification for regular disconnected states.
vpn.updateState(DetailedState.DISCONNECTED, TAG); vpn.updateState(DetailedState.DISCONNECTED, TAG);
order.verify(mNotificationManager, atLeastOnce()) order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
.cancelAsUser(anyString(), anyInt(), eq(userHandle));
// Start showing a notification for disconnected once always-on. // Start showing a notification for disconnected once always-on.
vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore); vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore);
order.verify(mNotificationManager) order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
// Stop showing the notification once connected. // Stop showing the notification once connected.
vpn.updateState(DetailedState.CONNECTED, TAG); vpn.updateState(DetailedState.CONNECTED, TAG);
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); order.verify(mNotificationManager).cancel(anyString(), anyInt());
// Show the notification if we disconnect again. // Show the notification if we disconnect again.
vpn.updateState(DetailedState.DISCONNECTED, TAG); vpn.updateState(DetailedState.DISCONNECTED, TAG);
order.verify(mNotificationManager) order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
// Notification should be cleared after unsetting always-on package. // Notification should be cleared after unsetting always-on package.
vpn.setAlwaysOnPackage(null, false, null, mKeyStore); vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); order.verify(mNotificationManager).cancel(anyString(), anyInt());
} }
@Test @Test
@@ -1272,6 +1273,10 @@ public class VpnTest {
* Mock some methods of vpn object. * Mock some methods of vpn object.
*/ */
private Vpn createVpn(@UserIdInt int userId) { private Vpn createVpn(@UserIdInt int userId) {
final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext);
return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService, return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator); userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
} }