Loading core/java/android/net/ConnectivityDiagnosticsManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -676,7 +676,8 @@ public class ConnectivityDiagnosticsManager { } try { mService.registerConnectivityDiagnosticsCallback(binder, request); mService.registerConnectivityDiagnosticsCallback( binder, request, mContext.getOpPackageName()); } catch (RemoteException exception) { exception.rethrowFromSystemServer(); } Loading core/java/android/net/IConnectivityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -222,7 +222,7 @@ interface IConnectivityManager boolean isCallerCurrentAlwaysOnVpnLockdownApp(); void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback, in NetworkRequest request); in NetworkRequest request, String callingPackageName); void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); IBinder startOrGetTestNetworkService(); Loading core/java/android/net/NetworkCapabilities.java +2 −2 Original line number Diff line number Diff line Loading @@ -858,8 +858,8 @@ public final class NetworkCapabilities implements Parcelable { * * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator. * * <p>An app is granted owner privileges over Networks that it supplies. Owner privileges * implicitly include administrator privileges. * <p>An app is granted owner privileges over Networks that it supplies. The owner UID MUST * always be included in administratorUids. * * @param administratorUids the UIDs to be set as administrators of this Network. * @hide Loading services/core/java/com/android/server/ConnectivityService.java +266 −88 Original line number Diff line number Diff line Loading @@ -48,8 +48,11 @@ import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static java.util.Map.Entry; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.NotificationManager; import android.app.PendingIntent; Loading @@ -62,6 +65,7 @@ import android.content.res.Configuration; import android.database.ContentObserver; import android.net.CaptivePortal; import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityManager; import android.net.ICaptivePortal; import android.net.IConnectivityDiagnosticsCallback; Loading Loading @@ -130,6 +134,7 @@ import android.os.Message; import android.os.Messenger; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; Loading Loading @@ -170,6 +175,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; Loading Loading @@ -492,9 +498,9 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has * been tested. * obj = String representing URL that Internet probe was redirect to, if it was redirected. * arg1 = One of the NETWORK_TESTED_RESULT_* constants. * arg2 = NetID. * obj = {@link NetworkTestedResults} representing information sent from NetworkMonitor. * data = PersistableBundle of extras passed from NetworkMonitor. If {@link * NetworkMonitorCallbacks#notifyNetworkTested} is called, this will be null. */ private static final int EVENT_NETWORK_TESTED = 41; Loading Loading @@ -596,6 +602,9 @@ public class ConnectivityService extends IConnectivityManager.Stub private Set<String> mWolSupportedInterfaces; private TelephonyManager mTelephonyManager; private final AppOpsManager mAppOpsManager; private final LocationPermissionChecker mLocationPermissionChecker; private KeepaliveTracker mKeepaliveTracker; private NetworkNotificationManager mNotifier; Loading Loading @@ -992,6 +1001,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetd = netd; mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); // To ensure uid rules are synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService Loading Loading @@ -2101,6 +2112,12 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } private boolean checkNetworkStackPermission(int pid, int uid) { return checkAnyPermissionOf(pid, uid, android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) { return checkAnyPermissionOf(pid, uid, android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP, Loading Loading @@ -2747,15 +2764,79 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case EVENT_NETWORK_TESTED: { final NetworkTestedResults results = (NetworkTestedResults) msg.obj; final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(results.mNetId); if (nai == null) break; handleNetworkTested(nai, results.mTestResult, (results.mRedirectUrl == null) ? "" : results.mRedirectUrl); // Invoke ConnectivityReport generation for this Network test event. final Message m = mConnectivityDiagnosticsHandler.obtainMessage( ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED, new ConnectivityReportEvent(results.mTimestampMillis, nai)); m.setData(msg.getData()); mConnectivityDiagnosticsHandler.sendMessage(m); break; } case EVENT_PROVISIONING_NOTIFICATION: { final int netId = msg.arg2; final boolean visible = toBool(msg.arg1); final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); // If captive portal status has changed, update capabilities or disconnect. if (nai != null && (visible != nai.lastCaptivePortalDetected)) { final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.name()); nai.asyncChannel.sendMessage( NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); teardownUnneededNetwork(nai); break; } updateCapabilities(oldScore, nai, nai.networkCapabilities); } if (!visible) { // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other // notifications belong to the same network may be cleared unexpectedly. mNotifier.clearNotification(netId, NotificationType.SIGN_IN); mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH); } else { if (nai == null) { loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor"); break; } if (!nai.networkAgentConfig.provisioningNotificationDisabled) { mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null, (PendingIntent) msg.obj, nai.networkAgentConfig.explicitlySelected); } } break; } case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: { final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); if (nai == null) break; updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); break; } } return true; } private void handleNetworkTested( @NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) { final boolean wasPartial = nai.partialConnectivity; nai.partialConnectivity = ((msg.arg1 & NETWORK_VALIDATION_RESULT_PARTIAL) != 0); nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0); final boolean partialConnectivityChanged = (wasPartial != nai.partialConnectivity); final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean wasValidated = nai.lastValidated; final boolean wasDefault = isDefaultNetwork(nai); // Only show a connected notification if the network is pending validation Loading @@ -2766,8 +2847,6 @@ public class ConnectivityService extends IConnectivityManager.Stub showNetworkNotification(nai, NotificationType.LOGGED_IN); } final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : ""; if (DBG) { final String logMsg = !TextUtils.isEmpty(redirectUrl) ? " with redirect to " + redirectUrl Loading Loading @@ -2829,54 +2908,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (wasValidated && !nai.lastValidated) { handleNetworkUnvalidated(nai); } break; } case EVENT_PROVISIONING_NOTIFICATION: { final int netId = msg.arg2; final boolean visible = toBool(msg.arg1); final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); // If captive portal status has changed, update capabilities or disconnect. if (nai != null && (visible != nai.lastCaptivePortalDetected)) { final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.name()); nai.asyncChannel.sendMessage( NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); teardownUnneededNetwork(nai); break; } updateCapabilities(oldScore, nai, nai.networkCapabilities); } if (!visible) { // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other // notifications belong to the same network may be cleared unexpectedly. mNotifier.clearNotification(netId, NotificationType.SIGN_IN); mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH); } else { if (nai == null) { loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor"); break; } if (!nai.networkAgentConfig.provisioningNotificationDisabled) { mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null, (PendingIntent) msg.obj, nai.networkAgentConfig.explicitlySelected); } } break; } case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: { final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); if (nai == null) break; updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); break; } } return true; } private int getCaptivePortalMode() { Loading Loading @@ -2927,8 +2958,23 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) { mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED, testResult, mNetId, redirectUrl)); notifyNetworkTestedWithExtras(testResult, redirectUrl, SystemClock.elapsedRealtime(), PersistableBundle.EMPTY); } @Override public void notifyNetworkTestedWithExtras( int testResult, @Nullable String redirectUrl, long timestampMillis, @NonNull PersistableBundle extras) { final Message msg = mTrackerHandler.obtainMessage( EVENT_NETWORK_TESTED, new NetworkTestedResults( mNetId, testResult, timestampMillis, redirectUrl)); msg.setData(new Bundle(extras)); mTrackerHandler.sendMessage(msg); } @Override Loading Loading @@ -7373,7 +7419,11 @@ public class ConnectivityService extends IConnectivityManager.Stub @GuardedBy("mVpns") private Vpn getVpnIfOwner() { final int uid = Binder.getCallingUid(); return getVpnIfOwner(Binder.getCallingUid()); } @GuardedBy("mVpns") private Vpn getVpnIfOwner(int uid) { final int user = UserHandle.getUserId(uid); final Vpn vpn = mVpns.get(user); Loading Loading @@ -7485,6 +7535,17 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2; /** * Event for {@link NetworkStateTrackerHandler} to trigger ConnectivityReport callbacks * after processing {@link #EVENT_NETWORK_TESTED} events. * obj = {@link ConnectivityReportEvent} representing ConnectivityReport info reported from * NetworkMonitor. * data = PersistableBundle of extras passed from NetworkMonitor. * * <p>See {@link ConnectivityService#EVENT_NETWORK_TESTED}. */ private static final int EVENT_NETWORK_TESTED = ConnectivityService.EVENT_NETWORK_TESTED; private ConnectivityDiagnosticsHandler(Looper looper) { super(looper); } Loading @@ -7502,6 +7563,19 @@ public class ConnectivityService extends IConnectivityManager.Stub (IConnectivityDiagnosticsCallback) msg.obj, msg.arg1); break; } case EVENT_NETWORK_TESTED: { final ConnectivityReportEvent reportEvent = (ConnectivityReportEvent) msg.obj; // This is safe because {@link // NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} receives a // PersistableBundle and converts it to the Bundle in the incoming Message. If // {@link NetworkMonitorCallbacks#notifyNetworkTested} is called, msg.data will // not be set. This is also safe, as msg.getData() will return an empty Bundle. final PersistableBundle extras = new PersistableBundle(msg.getData()); handleNetworkTestedWithExtras(reportEvent, extras); break; } } } } Loading @@ -7511,12 +7585,16 @@ public class ConnectivityService extends IConnectivityManager.Stub class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient { @NonNull private final IConnectivityDiagnosticsCallback mCb; @NonNull private final NetworkRequestInfo mRequestInfo; @NonNull private final String mCallingPackageName; @VisibleForTesting ConnectivityDiagnosticsCallbackInfo( @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) { @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri, @NonNull String callingPackageName) { mCb = cb; mRequestInfo = nri; mCallingPackageName = callingPackageName; } @Override Loading @@ -7526,6 +7604,39 @@ public class ConnectivityService extends IConnectivityManager.Stub } } /** * Class used for sending information from {@link * NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} to the handler for processing it. */ private static class NetworkTestedResults { private final int mNetId; private final int mTestResult; private final long mTimestampMillis; @Nullable private final String mRedirectUrl; private NetworkTestedResults( int netId, int testResult, long timestampMillis, @Nullable String redirectUrl) { mNetId = netId; mTestResult = testResult; mTimestampMillis = timestampMillis; mRedirectUrl = redirectUrl; } } /** * Class used for sending information from {@link NetworkStateTrackerHandler} to {@link * ConnectivityDiagnosticsHandler}. */ private static class ConnectivityReportEvent { private final long mTimestampMillis; @NonNull private final NetworkAgentInfo mNai; private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai) { mTimestampMillis = timestampMillis; mNai = nai; } } private void handleRegisterConnectivityDiagnosticsCallback( @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) { ensureRunningOnConnectivityServiceThread(); Loading Loading @@ -7573,13 +7684,80 @@ public class ConnectivityService extends IConnectivityManager.Stub cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0); } private void handleNetworkTestedWithExtras( @NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) { final NetworkAgentInfo nai = reportEvent.mNai; final ConnectivityReport report = new ConnectivityReport( reportEvent.mNai.network, reportEvent.mTimestampMillis, nai.linkProperties, nai.networkCapabilities, extras); final List<IConnectivityDiagnosticsCallback> results = getMatchingPermissionedCallbacks(nai); for (final IConnectivityDiagnosticsCallback cb : results) { try { cb.onConnectivityReport(report); } catch (RemoteException ex) { loge("Error invoking onConnectivityReport", ex); } } } private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks( @NonNull NetworkAgentInfo nai) { final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>(); for (Entry<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo> entry : mConnectivityDiagnosticsCallbacks.entrySet()) { final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue(); final NetworkRequestInfo nri = cbInfo.mRequestInfo; if (nai.satisfies(nri.request)) { if (checkConnectivityDiagnosticsPermissions( nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) { results.add(entry.getKey()); } } } return results; } @VisibleForTesting boolean checkConnectivityDiagnosticsPermissions( int callbackPid, int callbackUid, NetworkAgentInfo nai, String callbackPackageName) { if (checkNetworkStackPermission(callbackPid, callbackUid)) { return true; } if (!mLocationPermissionChecker.checkLocationPermission( callbackPackageName, null /* featureId */, callbackUid, null /* message */)) { return false; } synchronized (mVpns) { if (getVpnIfOwner(callbackUid) != null) { return true; } } // Administrator UIDs also contains the Owner UID if (nai.networkCapabilities.getAdministratorUids().contains(callbackUid)) { return true; } return false; } @Override public void registerConnectivityDiagnosticsCallback( @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) { @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request, @NonNull String callingPackageName) { if (request.legacyType != TYPE_NONE) { throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated." + " Please use NetworkCapabilities instead."); } mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName); // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid // and administrator uids to be safe. Loading @@ -7597,7 +7775,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // callback's binder death. final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId); final ConnectivityDiagnosticsCallbackInfo cbInfo = new ConnectivityDiagnosticsCallbackInfo(callback, nri); new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName); mConnectivityDiagnosticsHandler.sendMessage( mConnectivityDiagnosticsHandler.obtainMessage( Loading tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +11 −4 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.content.Context; import android.os.PersistableBundle; import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -58,21 +60,26 @@ public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); @Mock private Context mContext; @Mock private IConnectivityManager mService; @Mock private ConnectivityDiagnosticsCallback mCb; private Context mContext; private ConnectivityDiagnosticsBinder mBinder; private ConnectivityDiagnosticsManager mManager; private String mPackageName; @Before public void setUp() { mContext = mock(Context.class); mContext = InstrumentationRegistry.getContext(); mService = mock(IConnectivityManager.class); mCb = mock(ConnectivityDiagnosticsCallback.class); mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR); mManager = new ConnectivityDiagnosticsManager(mContext, mService); mPackageName = mContext.getOpPackageName(); } @After Loading Loading @@ -271,7 +278,7 @@ public class ConnectivityDiagnosticsManagerTest { mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); verify(mService).registerConnectivityDiagnosticsCallback( any(ConnectivityDiagnosticsBinder.class), eq(request)); any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName)); assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); } Loading Loading @@ -302,7 +309,7 @@ public class ConnectivityDiagnosticsManagerTest { // verify that re-registering is successful mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); verify(mService, times(2)).registerConnectivityDiagnosticsCallback( any(ConnectivityDiagnosticsBinder.class), eq(request)); any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName)); assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); } Loading Loading
core/java/android/net/ConnectivityDiagnosticsManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -676,7 +676,8 @@ public class ConnectivityDiagnosticsManager { } try { mService.registerConnectivityDiagnosticsCallback(binder, request); mService.registerConnectivityDiagnosticsCallback( binder, request, mContext.getOpPackageName()); } catch (RemoteException exception) { exception.rethrowFromSystemServer(); } Loading
core/java/android/net/IConnectivityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -222,7 +222,7 @@ interface IConnectivityManager boolean isCallerCurrentAlwaysOnVpnLockdownApp(); void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback, in NetworkRequest request); in NetworkRequest request, String callingPackageName); void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); IBinder startOrGetTestNetworkService(); Loading
core/java/android/net/NetworkCapabilities.java +2 −2 Original line number Diff line number Diff line Loading @@ -858,8 +858,8 @@ public final class NetworkCapabilities implements Parcelable { * * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator. * * <p>An app is granted owner privileges over Networks that it supplies. Owner privileges * implicitly include administrator privileges. * <p>An app is granted owner privileges over Networks that it supplies. The owner UID MUST * always be included in administratorUids. * * @param administratorUids the UIDs to be set as administrators of this Network. * @hide Loading
services/core/java/com/android/server/ConnectivityService.java +266 −88 Original line number Diff line number Diff line Loading @@ -48,8 +48,11 @@ import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static java.util.Map.Entry; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.NotificationManager; import android.app.PendingIntent; Loading @@ -62,6 +65,7 @@ import android.content.res.Configuration; import android.database.ContentObserver; import android.net.CaptivePortal; import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityManager; import android.net.ICaptivePortal; import android.net.IConnectivityDiagnosticsCallback; Loading Loading @@ -130,6 +134,7 @@ import android.os.Message; import android.os.Messenger; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; Loading Loading @@ -170,6 +175,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; Loading Loading @@ -492,9 +498,9 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has * been tested. * obj = String representing URL that Internet probe was redirect to, if it was redirected. * arg1 = One of the NETWORK_TESTED_RESULT_* constants. * arg2 = NetID. * obj = {@link NetworkTestedResults} representing information sent from NetworkMonitor. * data = PersistableBundle of extras passed from NetworkMonitor. If {@link * NetworkMonitorCallbacks#notifyNetworkTested} is called, this will be null. */ private static final int EVENT_NETWORK_TESTED = 41; Loading Loading @@ -596,6 +602,9 @@ public class ConnectivityService extends IConnectivityManager.Stub private Set<String> mWolSupportedInterfaces; private TelephonyManager mTelephonyManager; private final AppOpsManager mAppOpsManager; private final LocationPermissionChecker mLocationPermissionChecker; private KeepaliveTracker mKeepaliveTracker; private NetworkNotificationManager mNotifier; Loading Loading @@ -992,6 +1001,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetd = netd; mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); // To ensure uid rules are synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService Loading Loading @@ -2101,6 +2112,12 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } private boolean checkNetworkStackPermission(int pid, int uid) { return checkAnyPermissionOf(pid, uid, android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) { return checkAnyPermissionOf(pid, uid, android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP, Loading Loading @@ -2747,15 +2764,79 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case EVENT_NETWORK_TESTED: { final NetworkTestedResults results = (NetworkTestedResults) msg.obj; final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(results.mNetId); if (nai == null) break; handleNetworkTested(nai, results.mTestResult, (results.mRedirectUrl == null) ? "" : results.mRedirectUrl); // Invoke ConnectivityReport generation for this Network test event. final Message m = mConnectivityDiagnosticsHandler.obtainMessage( ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED, new ConnectivityReportEvent(results.mTimestampMillis, nai)); m.setData(msg.getData()); mConnectivityDiagnosticsHandler.sendMessage(m); break; } case EVENT_PROVISIONING_NOTIFICATION: { final int netId = msg.arg2; final boolean visible = toBool(msg.arg1); final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); // If captive portal status has changed, update capabilities or disconnect. if (nai != null && (visible != nai.lastCaptivePortalDetected)) { final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.name()); nai.asyncChannel.sendMessage( NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); teardownUnneededNetwork(nai); break; } updateCapabilities(oldScore, nai, nai.networkCapabilities); } if (!visible) { // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other // notifications belong to the same network may be cleared unexpectedly. mNotifier.clearNotification(netId, NotificationType.SIGN_IN); mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH); } else { if (nai == null) { loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor"); break; } if (!nai.networkAgentConfig.provisioningNotificationDisabled) { mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null, (PendingIntent) msg.obj, nai.networkAgentConfig.explicitlySelected); } } break; } case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: { final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); if (nai == null) break; updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); break; } } return true; } private void handleNetworkTested( @NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) { final boolean wasPartial = nai.partialConnectivity; nai.partialConnectivity = ((msg.arg1 & NETWORK_VALIDATION_RESULT_PARTIAL) != 0); nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0); final boolean partialConnectivityChanged = (wasPartial != nai.partialConnectivity); final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean wasValidated = nai.lastValidated; final boolean wasDefault = isDefaultNetwork(nai); // Only show a connected notification if the network is pending validation Loading @@ -2766,8 +2847,6 @@ public class ConnectivityService extends IConnectivityManager.Stub showNetworkNotification(nai, NotificationType.LOGGED_IN); } final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : ""; if (DBG) { final String logMsg = !TextUtils.isEmpty(redirectUrl) ? " with redirect to " + redirectUrl Loading Loading @@ -2829,54 +2908,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (wasValidated && !nai.lastValidated) { handleNetworkUnvalidated(nai); } break; } case EVENT_PROVISIONING_NOTIFICATION: { final int netId = msg.arg2; final boolean visible = toBool(msg.arg1); final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); // If captive portal status has changed, update capabilities or disconnect. if (nai != null && (visible != nai.lastCaptivePortalDetected)) { final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.name()); nai.asyncChannel.sendMessage( NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); teardownUnneededNetwork(nai); break; } updateCapabilities(oldScore, nai, nai.networkCapabilities); } if (!visible) { // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other // notifications belong to the same network may be cleared unexpectedly. mNotifier.clearNotification(netId, NotificationType.SIGN_IN); mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH); } else { if (nai == null) { loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor"); break; } if (!nai.networkAgentConfig.provisioningNotificationDisabled) { mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null, (PendingIntent) msg.obj, nai.networkAgentConfig.explicitlySelected); } } break; } case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: { final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); if (nai == null) break; updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); break; } } return true; } private int getCaptivePortalMode() { Loading Loading @@ -2927,8 +2958,23 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) { mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED, testResult, mNetId, redirectUrl)); notifyNetworkTestedWithExtras(testResult, redirectUrl, SystemClock.elapsedRealtime(), PersistableBundle.EMPTY); } @Override public void notifyNetworkTestedWithExtras( int testResult, @Nullable String redirectUrl, long timestampMillis, @NonNull PersistableBundle extras) { final Message msg = mTrackerHandler.obtainMessage( EVENT_NETWORK_TESTED, new NetworkTestedResults( mNetId, testResult, timestampMillis, redirectUrl)); msg.setData(new Bundle(extras)); mTrackerHandler.sendMessage(msg); } @Override Loading Loading @@ -7373,7 +7419,11 @@ public class ConnectivityService extends IConnectivityManager.Stub @GuardedBy("mVpns") private Vpn getVpnIfOwner() { final int uid = Binder.getCallingUid(); return getVpnIfOwner(Binder.getCallingUid()); } @GuardedBy("mVpns") private Vpn getVpnIfOwner(int uid) { final int user = UserHandle.getUserId(uid); final Vpn vpn = mVpns.get(user); Loading Loading @@ -7485,6 +7535,17 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2; /** * Event for {@link NetworkStateTrackerHandler} to trigger ConnectivityReport callbacks * after processing {@link #EVENT_NETWORK_TESTED} events. * obj = {@link ConnectivityReportEvent} representing ConnectivityReport info reported from * NetworkMonitor. * data = PersistableBundle of extras passed from NetworkMonitor. * * <p>See {@link ConnectivityService#EVENT_NETWORK_TESTED}. */ private static final int EVENT_NETWORK_TESTED = ConnectivityService.EVENT_NETWORK_TESTED; private ConnectivityDiagnosticsHandler(Looper looper) { super(looper); } Loading @@ -7502,6 +7563,19 @@ public class ConnectivityService extends IConnectivityManager.Stub (IConnectivityDiagnosticsCallback) msg.obj, msg.arg1); break; } case EVENT_NETWORK_TESTED: { final ConnectivityReportEvent reportEvent = (ConnectivityReportEvent) msg.obj; // This is safe because {@link // NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} receives a // PersistableBundle and converts it to the Bundle in the incoming Message. If // {@link NetworkMonitorCallbacks#notifyNetworkTested} is called, msg.data will // not be set. This is also safe, as msg.getData() will return an empty Bundle. final PersistableBundle extras = new PersistableBundle(msg.getData()); handleNetworkTestedWithExtras(reportEvent, extras); break; } } } } Loading @@ -7511,12 +7585,16 @@ public class ConnectivityService extends IConnectivityManager.Stub class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient { @NonNull private final IConnectivityDiagnosticsCallback mCb; @NonNull private final NetworkRequestInfo mRequestInfo; @NonNull private final String mCallingPackageName; @VisibleForTesting ConnectivityDiagnosticsCallbackInfo( @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) { @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri, @NonNull String callingPackageName) { mCb = cb; mRequestInfo = nri; mCallingPackageName = callingPackageName; } @Override Loading @@ -7526,6 +7604,39 @@ public class ConnectivityService extends IConnectivityManager.Stub } } /** * Class used for sending information from {@link * NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} to the handler for processing it. */ private static class NetworkTestedResults { private final int mNetId; private final int mTestResult; private final long mTimestampMillis; @Nullable private final String mRedirectUrl; private NetworkTestedResults( int netId, int testResult, long timestampMillis, @Nullable String redirectUrl) { mNetId = netId; mTestResult = testResult; mTimestampMillis = timestampMillis; mRedirectUrl = redirectUrl; } } /** * Class used for sending information from {@link NetworkStateTrackerHandler} to {@link * ConnectivityDiagnosticsHandler}. */ private static class ConnectivityReportEvent { private final long mTimestampMillis; @NonNull private final NetworkAgentInfo mNai; private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai) { mTimestampMillis = timestampMillis; mNai = nai; } } private void handleRegisterConnectivityDiagnosticsCallback( @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) { ensureRunningOnConnectivityServiceThread(); Loading Loading @@ -7573,13 +7684,80 @@ public class ConnectivityService extends IConnectivityManager.Stub cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0); } private void handleNetworkTestedWithExtras( @NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) { final NetworkAgentInfo nai = reportEvent.mNai; final ConnectivityReport report = new ConnectivityReport( reportEvent.mNai.network, reportEvent.mTimestampMillis, nai.linkProperties, nai.networkCapabilities, extras); final List<IConnectivityDiagnosticsCallback> results = getMatchingPermissionedCallbacks(nai); for (final IConnectivityDiagnosticsCallback cb : results) { try { cb.onConnectivityReport(report); } catch (RemoteException ex) { loge("Error invoking onConnectivityReport", ex); } } } private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks( @NonNull NetworkAgentInfo nai) { final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>(); for (Entry<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo> entry : mConnectivityDiagnosticsCallbacks.entrySet()) { final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue(); final NetworkRequestInfo nri = cbInfo.mRequestInfo; if (nai.satisfies(nri.request)) { if (checkConnectivityDiagnosticsPermissions( nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) { results.add(entry.getKey()); } } } return results; } @VisibleForTesting boolean checkConnectivityDiagnosticsPermissions( int callbackPid, int callbackUid, NetworkAgentInfo nai, String callbackPackageName) { if (checkNetworkStackPermission(callbackPid, callbackUid)) { return true; } if (!mLocationPermissionChecker.checkLocationPermission( callbackPackageName, null /* featureId */, callbackUid, null /* message */)) { return false; } synchronized (mVpns) { if (getVpnIfOwner(callbackUid) != null) { return true; } } // Administrator UIDs also contains the Owner UID if (nai.networkCapabilities.getAdministratorUids().contains(callbackUid)) { return true; } return false; } @Override public void registerConnectivityDiagnosticsCallback( @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) { @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request, @NonNull String callingPackageName) { if (request.legacyType != TYPE_NONE) { throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated." + " Please use NetworkCapabilities instead."); } mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName); // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid // and administrator uids to be safe. Loading @@ -7597,7 +7775,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // callback's binder death. final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId); final ConnectivityDiagnosticsCallbackInfo cbInfo = new ConnectivityDiagnosticsCallbackInfo(callback, nri); new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName); mConnectivityDiagnosticsHandler.sendMessage( mConnectivityDiagnosticsHandler.obtainMessage( Loading
tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +11 −4 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.content.Context; import android.os.PersistableBundle; import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -58,21 +60,26 @@ public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); @Mock private Context mContext; @Mock private IConnectivityManager mService; @Mock private ConnectivityDiagnosticsCallback mCb; private Context mContext; private ConnectivityDiagnosticsBinder mBinder; private ConnectivityDiagnosticsManager mManager; private String mPackageName; @Before public void setUp() { mContext = mock(Context.class); mContext = InstrumentationRegistry.getContext(); mService = mock(IConnectivityManager.class); mCb = mock(ConnectivityDiagnosticsCallback.class); mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR); mManager = new ConnectivityDiagnosticsManager(mContext, mService); mPackageName = mContext.getOpPackageName(); } @After Loading Loading @@ -271,7 +278,7 @@ public class ConnectivityDiagnosticsManagerTest { mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); verify(mService).registerConnectivityDiagnosticsCallback( any(ConnectivityDiagnosticsBinder.class), eq(request)); any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName)); assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); } Loading Loading @@ -302,7 +309,7 @@ public class ConnectivityDiagnosticsManagerTest { // verify that re-registering is successful mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); verify(mService, times(2)).registerConnectivityDiagnosticsCallback( any(ConnectivityDiagnosticsBinder.class), eq(request)); any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName)); assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); } Loading