diff --git a/Tethering/Android.bp b/Tethering/Android.bp index d3b9393d63..6031646d61 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -37,6 +37,7 @@ java_defaults { "networkstack-client", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", + "android.hardware.tetheroffload.control-V1.1-java", "net-utils-framework-common", "net-utils-device-common", "netd-client", diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 88c77b07e7..44e3916bdf 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -26,6 +26,7 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import android.annotation.NonNull; @@ -96,7 +97,8 @@ public class OffloadController { private final SharedLog mLog; private final HashMap mDownstreams; private boolean mConfigInitialized; - private boolean mControlInitialized; + @OffloadHardwareInterface.OffloadHalVersion + private int mControlHalVersion; private LinkProperties mUpstreamLinkProperties; // The complete set of offload-exempt prefixes passed in via Tethering from // all upstream and downstream sources. @@ -179,7 +181,7 @@ public class OffloadController { } } - mControlInitialized = mHwInterface.initOffloadControl( + mControlHalVersion = mHwInterface.initOffloadControl( // OffloadHardwareInterface guarantees that these callback // methods are called on the handler passed to it, which is the // same as mHandler, as coordinated by the setup in Tethering. @@ -278,7 +280,7 @@ public class OffloadController { updateStatsForCurrentUpstream(); mUpstreamLinkProperties = null; mHwInterface.stopOffloadControl(); - mControlInitialized = false; + mControlHalVersion = OFFLOAD_HAL_VERSION_NONE; mConfigInitialized = false; if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); @@ -287,7 +289,7 @@ public class OffloadController { } private boolean started() { - return mConfigInitialized && mControlInitialized; + return mConfigInitialized && mControlHalVersion != OFFLOAD_HAL_VERSION_NONE; } @VisibleForTesting @@ -696,6 +698,8 @@ public class OffloadController { } final boolean isStarted = started(); pw.println("Offload HALs " + (isStarted ? "started" : "not started")); + pw.println("Offload Control HAL version: " + + OffloadHardwareInterface.halVerToString(mControlHalVersion)); LinkProperties lp = mUpstreamLinkProperties; String upstream = (lp != null) ? lp.getInterfaceName() : null; pw.println("Current upstream: " + upstream); diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index da5f25b2a5..7685847680 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -20,6 +20,7 @@ import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; import static android.net.util.TetheringUtils.uint16; +import android.annotation.IntDef; import android.annotation.NonNull; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; @@ -38,12 +39,15 @@ import android.os.RemoteException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.IOException; import java.io.InterruptedIOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; @@ -82,6 +86,37 @@ public class OffloadHardwareInterface { private final SharedLog mLog; private final Dependencies mDeps; private IOffloadControl mOffloadControl; + + // TODO: Use major-minor version control to prevent from defining new constants. + static final int OFFLOAD_HAL_VERSION_NONE = 0; + static final int OFFLOAD_HAL_VERSION_1_0 = 1; + static final int OFFLOAD_HAL_VERSION_1_1 = 2; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "OFFLOAD_HAL_VERSION_", value = { + OFFLOAD_HAL_VERSION_NONE, + OFFLOAD_HAL_VERSION_1_0, + OFFLOAD_HAL_VERSION_1_1 + }) + public @interface OffloadHalVersion {} + @OffloadHalVersion + private int mOffloadControlVersion = OFFLOAD_HAL_VERSION_NONE; + + @NonNull + static String halVerToString(int version) { + switch(version) { + case OFFLOAD_HAL_VERSION_1_0: + return "1.0"; + case OFFLOAD_HAL_VERSION_1_1: + return "1.1"; + case OFFLOAD_HAL_VERSION_NONE: + return "None"; + default: + throw new IllegalArgumentException("Unsupported version int " + version); + } + + } + private TetheringOffloadCallback mTetheringOffloadCallback; private ControlCallback mControlCallback; @@ -167,13 +202,30 @@ public class OffloadHardwareInterface { } } - public IOffloadControl getOffloadControl() { + @NonNull + public Pair getOffloadControl() { + IOffloadControl hal = null; + int version = OFFLOAD_HAL_VERSION_NONE; try { - return IOffloadControl.getService(true /*retry*/); - } catch (RemoteException | NoSuchElementException e) { - mLog.e("tethering offload control not supported: " + e); - return null; + hal = android.hardware.tetheroffload.control + .V1_1.IOffloadControl.getService(true /*retry*/); + version = OFFLOAD_HAL_VERSION_1_1; + } catch (NoSuchElementException e) { + // Unsupported by device. + } catch (RemoteException e) { + mLog.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_1_1); } + if (hal == null) { + try { + hal = IOffloadControl.getService(true /*retry*/); + version = OFFLOAD_HAL_VERSION_1_0; + } catch (NoSuchElementException e) { + // Unsupported by device. + } catch (RemoteException e) { + mLog.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_1_0); + } + } + return new Pair(hal, version); } public NativeHandle createConntrackSocket(final int groups) { @@ -304,16 +356,25 @@ public class OffloadHardwareInterface { } } - /** Initialize the tethering offload HAL. */ - public boolean initOffloadControl(ControlCallback controlCb) { + /** + * Initialize the tethering offload HAL. + * + * @return one of {@code OFFLOAD_HAL_VERSION_*} represents the HAL version, or + * {@link #OFFLOAD_HAL_VERSION_NONE} if failed. + */ + public int initOffloadControl(ControlCallback controlCb) { mControlCallback = controlCb; if (mOffloadControl == null) { - mOffloadControl = mDeps.getOffloadControl(); + final Pair halAndVersion = mDeps.getOffloadControl(); + mOffloadControl = halAndVersion.first; + mOffloadControlVersion = halAndVersion.second; if (mOffloadControl == null) { mLog.e("tethering IOffloadControl.getService() returned null"); - return false; + return OFFLOAD_HAL_VERSION_NONE; } + mLog.i("tethering offload control version " + + halVerToString(mOffloadControlVersion) + " is supported."); } final String logmsg = String.format("initOffloadControl(%s)", @@ -331,11 +392,11 @@ public class OffloadHardwareInterface { }); } catch (RemoteException e) { record(logmsg, e); - return false; + return OFFLOAD_HAL_VERSION_NONE; } record(logmsg, results); - return results.mSuccess; + return results.mSuccess ? mOffloadControlVersion : OFFLOAD_HAL_VERSION_NONE; } /** Stop IOffloadControl. */ diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index 9bd82f96de..88f205445e 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -29,6 +29,8 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import static com.android.testutils.MiscAsserts.assertContainsAll; import static com.android.testutils.MiscAsserts.assertThrows; @@ -141,10 +143,10 @@ public class OffloadControllerTest { FakeSettingsProvider.clearSettingsProvider(); } - private void setupFunctioningHardwareInterface() { + private void setupFunctioningHardwareInterface(int controlVersion) { when(mHardware.initOffloadConfig()).thenReturn(true); when(mHardware.initOffloadControl(mControlCallbackCaptor.capture())) - .thenReturn(true); + .thenReturn(controlVersion); when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true); when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats()); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); @@ -170,6 +172,7 @@ public class OffloadControllerTest { ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); verify(mStatsManager).registerNetworkStatsProvider(anyString(), tetherStatsProviderCaptor.capture()); + reset(mStatsManager); mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); assertNotNull(mTetherStatsProvider); mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); @@ -177,10 +180,18 @@ public class OffloadControllerTest { return offload; } + @Test + public void testStartStop() throws Exception { + stopOffloadController( + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/)); + stopOffloadController( + startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/)); + } + @NonNull - private OffloadController startOffloadController(boolean expectStart) + private OffloadController startOffloadController(int controlVersion, boolean expectStart) throws Exception { - setupFunctioningHardwareInterface(); + setupFunctioningHardwareInterface(controlVersion); final OffloadController offload = makeOffloadController(); offload.start(); @@ -208,7 +219,7 @@ public class OffloadControllerTest { when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1); assertThrows(SettingNotFoundException.class, () -> Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); - startOffloadController(false /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/); } @Test @@ -216,26 +227,26 @@ public class OffloadControllerTest { when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0); assertThrows(SettingNotFoundException.class, () -> Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); } @Test public void testSettingsAllowsStart() throws Exception { Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); } @Test public void testSettingsDisablesStart() throws Exception { Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1); - startOffloadController(false /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/); } @Test public void testSetUpstreamLinkPropertiesWorking() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); // In reality, the UpstreamNetworkMonitor would have passed down to us // a covering set of local prefixes representing a minimum essential @@ -406,7 +417,7 @@ public class OffloadControllerTest { public void testGetForwardedStats() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; @@ -496,7 +507,7 @@ public class OffloadControllerTest { public void testSetInterfaceQuota() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; @@ -558,7 +569,7 @@ public class OffloadControllerTest { public void testDataLimitCallback() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); @@ -569,7 +580,7 @@ public class OffloadControllerTest { public void testAddRemoveDownstreams() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); final InOrder inOrder = inOrder(mHardware); // Tethering makes several calls to setLocalPrefixes() before add/remove @@ -636,7 +647,7 @@ public class OffloadControllerTest { public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); // Pretend to set a few different upstreams (only the interface name // matters for this test; we're ignoring IP and route information). @@ -667,7 +678,7 @@ public class OffloadControllerTest { throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); // Pretend to set a few different upstreams (only the interface name // matters for this test; we're ignoring IP and route information). @@ -745,7 +756,7 @@ public class OffloadControllerTest { enableOffload(); setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); final OffloadController offload = - startOffloadController(true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); // Initialize with fake eth upstream. final String ethernetIface = "eth1"; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index 38b19dd3da..f4194e5d77 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -21,6 +21,8 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_UNIX; import static android.system.OsConstants.SOCK_STREAM; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -45,6 +47,7 @@ import android.os.test.TestLooper; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -91,8 +94,8 @@ public final class OffloadHardwareInterfaceTest { } @Override - public IOffloadControl getOffloadControl() { - return mIOffloadControl; + public Pair getOffloadControl() { + return new Pair(mIOffloadControl, OFFLOAD_HAL_VERSION_1_0); } @Override @@ -110,6 +113,7 @@ public final class OffloadHardwareInterfaceTest { mControlCallback = spy(new OffloadHardwareInterface.ControlCallback()); } + // TODO: Pass version to test version specific operations. private void startOffloadHardwareInterface() throws Exception { mOffloadHw.initOffloadConfig(); mOffloadHw.initOffloadControl(mControlCallback); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 383fce1e79..d277e30773 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -63,6 +63,8 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static com.android.networkstack.tethering.TestConnectivityManager.BROADCAST_FIRST; import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST; import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener; @@ -595,7 +597,7 @@ public class TetheringTest { mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) .thenReturn(true); - initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */, + initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, 0 /* defaultDisabled */); when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats); @@ -1866,7 +1868,7 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); // 1. Offload fail if no OffloadConfig. - initOffloadConfiguration(false /* offloadConfig */, true /* offloadControl */, + initOffloadConfiguration(false /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, 0 /* defaultDisabled */); runUsbTethering(upstreamState); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); @@ -1874,7 +1876,7 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); reset(mUsbManager, mIPv6TetheringCoordinator); // 2. Offload fail if no OffloadControl. - initOffloadConfiguration(true /* offloadConfig */, false /* offloadControl */, + initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_NONE, 0 /* defaultDisabled */); runUsbTethering(upstreamState); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); @@ -1882,7 +1884,7 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); reset(mUsbManager, mIPv6TetheringCoordinator); // 3. Offload fail if disabled by settings. - initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */, + initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, 1 /* defaultDisabled */); runUsbTethering(upstreamState); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); @@ -1900,9 +1902,10 @@ public class TetheringTest { } private void initOffloadConfiguration(final boolean offloadConfig, - final boolean offloadControl, final int defaultDisabled) { + @OffloadHardwareInterface.OffloadHalVersion final int offloadControlVersion, + final int defaultDisabled) { when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig); - when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControl); + when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControlVersion); when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn( defaultDisabled); }