diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 0b37fa51c3..4eaf973297 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -28,6 +28,7 @@ import static android.net.QosCallback.QosCallbackRegistrationException; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresApi; @@ -1207,6 +1208,16 @@ public class ConnectivityManager { }) public @interface FirewallRule {} + /** @hide */ + public static final long FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS = 1L; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @LongDef(flag = true, prefix = "FEATURE_", value = { + FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS + }) + public @interface ConnectivityManagerFeature {} + /** * A kludge to facilitate static access where a Context pointer isn't available, like in the * case of the static set/getProcessDefaultNetwork methods and from the Network class. @@ -1220,6 +1231,14 @@ public class ConnectivityManager { @GuardedBy("mTetheringEventCallbacks") private TetheringManager mTetheringManager; + private final Object mEnabledConnectivityManagerFeaturesLock = new Object(); + // mEnabledConnectivityManagerFeatures is lazy-loaded in this ConnectivityManager instance, but + // fetched from ConnectivityService, where it is loaded in ConnectivityService startup, so it + // should have consistent values. + @GuardedBy("sEnabledConnectivityManagerFeaturesLock") + @ConnectivityManagerFeature + private Long mEnabledConnectivityManagerFeatures = null; + private TetheringManager getTetheringManager() { synchronized (mTetheringEventCallbacks) { if (mTetheringManager == null) { @@ -4529,6 +4548,20 @@ public class ConnectivityManager { return request; } + private boolean isFeatureEnabled(@ConnectivityManagerFeature long connectivityManagerFeature) { + synchronized (mEnabledConnectivityManagerFeaturesLock) { + if (mEnabledConnectivityManagerFeatures == null) { + try { + mEnabledConnectivityManagerFeatures = + mService.getEnabledConnectivityManagerFeatures(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + return (mEnabledConnectivityManagerFeatures & connectivityManagerFeature) != 0; + } + } + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) { return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType, diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index 55c70856c7..f9de8edc92 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -259,4 +259,6 @@ interface IConnectivityManager void setTestLowTcpPollingTimerForKeepalive(long timeMs); IBinder getRoutingCoordinatorService(); + + long getEnabledConnectivityManagerFeatures(); } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index bb77a9d361..d3b7f793b1 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -489,6 +489,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private final boolean mRequestRestrictedWifiEnabled; private final boolean mBackgroundFirewallChainEnabled; + private final boolean mUseDeclaredMethodsForCallbacksEnabled; + /** * Uids ConnectivityService tracks blocked status of to send blocked status callbacks. * Key is uid based on mAsUid of registered networkRequestInfo @@ -1850,6 +1852,8 @@ public class ConnectivityService extends IConnectivityManager.Stub && mDeps.isFeatureEnabled(context, REQUEST_RESTRICTED_WIFI); mBackgroundFirewallChainEnabled = mDeps.isAtLeastV() && mDeps.isFeatureNotChickenedOut( context, ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN); + mUseDeclaredMethodsForCallbacksEnabled = mDeps.isFeatureEnabled(context, + ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS); mCarrierPrivilegeAuthenticator = mDeps.makeCarrierPrivilegeAuthenticator( mContext, mTelephonyManager, mRequestRestrictedWifiEnabled, this::handleUidCarrierPrivilegesLost, mHandler); @@ -14045,4 +14049,16 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceNetworkStackPermission(mContext); return mRoutingCoordinatorService; } + + @Override + public long getEnabledConnectivityManagerFeatures() { + long features = 0; + // The bitmask must be built based on final properties initialized in the constructor, to + // ensure that it does not change over time and is always consistent between + // ConnectivityManager and ConnectivityService. + if (mUseDeclaredMethodsForCallbacksEnabled) { + features |= ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS; + } + return features; + } } diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java index 7ea7f95723..1ee1ed7432 100644 --- a/service/src/com/android/server/connectivity/ConnectivityFlags.java +++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java @@ -46,6 +46,9 @@ public final class ConnectivityFlags { public static final String DELAY_DESTROY_SOCKETS = "delay_destroy_sockets"; + public static final String USE_DECLARED_METHODS_FOR_CALLBACKS = + "use_declared_methods_for_callbacks"; + private boolean mNoRematchAllRequestsOnRegister; /** diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 44a822251d..8526a9a9d3 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -2178,9 +2178,8 @@ public class ConnectivityServiceTest { switch (name) { case ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER: case ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK: - return true; case ConnectivityFlags.REQUEST_RESTRICTED_WIFI: - return true; + case ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS: case KEY_DESTROY_FROZEN_SOCKETS_VERSION: return true; default: diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 47a6763198..ed72fd2b59 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -164,6 +164,7 @@ open class CSTest { it[ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING] = true it[ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN] = true it[ConnectivityFlags.DELAY_DESTROY_SOCKETS] = true + it[ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS] = true } fun setFeatureEnabled(flag: String, enabled: Boolean) = enabledFeatures.set(flag, enabled)