Merge "Add Tetheroffload AIDL interface support"
This commit is contained in:
@@ -61,9 +61,13 @@ java_defaults {
|
|||||||
"modules-utils-build",
|
"modules-utils-build",
|
||||||
"modules-utils-statemachine",
|
"modules-utils-statemachine",
|
||||||
"networkstack-client",
|
"networkstack-client",
|
||||||
|
// AIDL tetheroffload implementation
|
||||||
|
"android.hardware.tetheroffload-V1-java",
|
||||||
|
// HIDL tetheroffload implementation
|
||||||
"android.hardware.tetheroffload.config-V1.0-java",
|
"android.hardware.tetheroffload.config-V1.0-java",
|
||||||
"android.hardware.tetheroffload.control-V1.0-java",
|
"android.hardware.tetheroffload.control-V1.0-java",
|
||||||
"android.hardware.tetheroffload.control-V1.1-java",
|
"android.hardware.tetheroffload.control-V1.1-java",
|
||||||
|
"android.hidl.manager-V1.2-java",
|
||||||
"net-utils-framework-common",
|
"net-utils-framework-common",
|
||||||
"net-utils-device-common",
|
"net-utils-device-common",
|
||||||
"net-utils-device-common-bpf",
|
"net-utils-device-common-bpf",
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/** Abstraction of Tetheroffload HAL interface */
|
||||||
|
interface IOffloadHal {
|
||||||
|
/*
|
||||||
|
* Initialize the Tetheroffload HAL. Offload management process need to know conntrack rules to
|
||||||
|
* support NAT, but it may not have permission to create netlink netfilter sockets. Create two
|
||||||
|
* netlink netfilter sockets and share them with offload management process.
|
||||||
|
*/
|
||||||
|
boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2,
|
||||||
|
@NonNull OffloadHalCallback callback);
|
||||||
|
|
||||||
|
/** Stop the Tetheroffload HAL. */
|
||||||
|
boolean stopOffload();
|
||||||
|
|
||||||
|
/** Get HAL interface version number. */
|
||||||
|
int getVersion();
|
||||||
|
|
||||||
|
/** Get Tx/Rx usage from last query. */
|
||||||
|
ForwardedStats getForwardedStats(@NonNull String upstream);
|
||||||
|
|
||||||
|
/** Set local prefixes to offload management process. */
|
||||||
|
boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes);
|
||||||
|
|
||||||
|
/** Set data limit value to offload management process. */
|
||||||
|
boolean setDataLimit(@NonNull String iface, long limit);
|
||||||
|
|
||||||
|
/** Set data warning and limit value to offload management process. */
|
||||||
|
boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit);
|
||||||
|
|
||||||
|
/** Set upstream parameters to offload management process. */
|
||||||
|
boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr,
|
||||||
|
@NonNull String v4gateway, @NonNull ArrayList<String> v6gws);
|
||||||
|
|
||||||
|
/** Add downstream prefix to offload management process. */
|
||||||
|
boolean addDownstream(@NonNull String ifname, @NonNull String prefix);
|
||||||
|
|
||||||
|
/** Remove downstream prefix from offload management process. */
|
||||||
|
boolean removeDownstream(@NonNull String ifname, @NonNull String prefix);
|
||||||
|
}
|
||||||
@@ -26,8 +26,8 @@ import static android.net.NetworkStats.UID_TETHERING;
|
|||||||
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
||||||
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
|
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
|
||||||
|
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
|
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 static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
|
||||||
|
|
||||||
@@ -98,9 +98,8 @@ public class OffloadController {
|
|||||||
private final OffloadTetheringStatsProvider mStatsProvider;
|
private final OffloadTetheringStatsProvider mStatsProvider;
|
||||||
private final SharedLog mLog;
|
private final SharedLog mLog;
|
||||||
private final HashMap<String, LinkProperties> mDownstreams;
|
private final HashMap<String, LinkProperties> mDownstreams;
|
||||||
private boolean mConfigInitialized;
|
|
||||||
@OffloadHardwareInterface.OffloadHalVersion
|
@OffloadHardwareInterface.OffloadHalVersion
|
||||||
private int mControlHalVersion;
|
private int mOffloadHalVersion;
|
||||||
private LinkProperties mUpstreamLinkProperties;
|
private LinkProperties mUpstreamLinkProperties;
|
||||||
// The complete set of offload-exempt prefixes passed in via Tethering from
|
// The complete set of offload-exempt prefixes passed in via Tethering from
|
||||||
// all upstream and downstream sources.
|
// all upstream and downstream sources.
|
||||||
@@ -205,20 +204,11 @@ public class OffloadController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mConfigInitialized) {
|
mOffloadHalVersion = mHwInterface.initOffload(
|
||||||
mConfigInitialized = mHwInterface.initOffloadConfig();
|
|
||||||
if (!mConfigInitialized) {
|
|
||||||
mLog.i("tethering offload config not supported");
|
|
||||||
stop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mControlHalVersion = mHwInterface.initOffloadControl(
|
|
||||||
// OffloadHardwareInterface guarantees that these callback
|
// OffloadHardwareInterface guarantees that these callback
|
||||||
// methods are called on the handler passed to it, which is the
|
// methods are called on the handler passed to it, which is the
|
||||||
// same as mHandler, as coordinated by the setup in Tethering.
|
// same as mHandler, as coordinated by the setup in Tethering.
|
||||||
new OffloadHardwareInterface.ControlCallback() {
|
new OffloadHardwareInterface.OffloadHalCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onStarted() {
|
public void onStarted() {
|
||||||
if (!started()) return;
|
if (!started()) return;
|
||||||
@@ -305,11 +295,11 @@ public class OffloadController {
|
|||||||
|
|
||||||
final boolean isStarted = started();
|
final boolean isStarted = started();
|
||||||
if (!isStarted) {
|
if (!isStarted) {
|
||||||
mLog.i("tethering offload control not supported");
|
mLog.i("tethering offload not supported");
|
||||||
stop();
|
stop();
|
||||||
} else {
|
} else {
|
||||||
mLog.log("tethering offload started, version: "
|
mLog.log("tethering offload started, version: "
|
||||||
+ OffloadHardwareInterface.halVerToString(mControlHalVersion));
|
+ OffloadHardwareInterface.halVerToString(mOffloadHalVersion));
|
||||||
mNatUpdateCallbacksReceived = 0;
|
mNatUpdateCallbacksReceived = 0;
|
||||||
mNatUpdateNetlinkErrors = 0;
|
mNatUpdateNetlinkErrors = 0;
|
||||||
maybeSchedulePollingStats();
|
maybeSchedulePollingStats();
|
||||||
@@ -325,9 +315,8 @@ public class OffloadController {
|
|||||||
final boolean wasStarted = started();
|
final boolean wasStarted = started();
|
||||||
updateStatsForCurrentUpstream();
|
updateStatsForCurrentUpstream();
|
||||||
mUpstreamLinkProperties = null;
|
mUpstreamLinkProperties = null;
|
||||||
mHwInterface.stopOffloadControl();
|
mHwInterface.stopOffload();
|
||||||
mControlHalVersion = OFFLOAD_HAL_VERSION_NONE;
|
mOffloadHalVersion = OFFLOAD_HAL_VERSION_NONE;
|
||||||
mConfigInitialized = false;
|
|
||||||
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
|
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
|
||||||
mHandler.removeCallbacks(mScheduledPollingTask);
|
mHandler.removeCallbacks(mScheduledPollingTask);
|
||||||
}
|
}
|
||||||
@@ -335,7 +324,7 @@ public class OffloadController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean started() {
|
private boolean started() {
|
||||||
return mConfigInitialized && mControlHalVersion != OFFLOAD_HAL_VERSION_NONE;
|
return mOffloadHalVersion != OFFLOAD_HAL_VERSION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -528,7 +517,7 @@ public class OffloadController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean useStatsPolling() {
|
private boolean useStatsPolling() {
|
||||||
return mControlHalVersion == OFFLOAD_HAL_VERSION_1_0;
|
return mOffloadHalVersion == OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean maybeUpdateDataWarningAndLimit(String iface) {
|
private boolean maybeUpdateDataWarningAndLimit(String iface) {
|
||||||
@@ -540,7 +529,7 @@ public class OffloadController {
|
|||||||
|
|
||||||
final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE);
|
final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE);
|
||||||
final boolean ret;
|
final boolean ret;
|
||||||
if (mControlHalVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (mOffloadHalVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
ret = mHwInterface.setDataWarningAndLimit(iface, quota.warningBytes, quota.limitBytes);
|
ret = mHwInterface.setDataWarningAndLimit(iface, quota.warningBytes, quota.limitBytes);
|
||||||
} else {
|
} else {
|
||||||
ret = mHwInterface.setDataLimit(iface, quota.limitBytes);
|
ret = mHwInterface.setDataLimit(iface, quota.limitBytes);
|
||||||
@@ -611,7 +600,7 @@ public class OffloadController {
|
|||||||
for (RouteInfo ri : oldRoutes) {
|
for (RouteInfo ri : oldRoutes) {
|
||||||
if (shouldIgnoreDownstreamRoute(ri)) continue;
|
if (shouldIgnoreDownstreamRoute(ri)) continue;
|
||||||
if (!newRoutes.contains(ri)) {
|
if (!newRoutes.contains(ri)) {
|
||||||
mHwInterface.removeDownstreamPrefix(ifname, ri.getDestination().toString());
|
mHwInterface.removeDownstream(ifname, ri.getDestination().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +608,7 @@ public class OffloadController {
|
|||||||
for (RouteInfo ri : newRoutes) {
|
for (RouteInfo ri : newRoutes) {
|
||||||
if (shouldIgnoreDownstreamRoute(ri)) continue;
|
if (shouldIgnoreDownstreamRoute(ri)) continue;
|
||||||
if (!oldRoutes.contains(ri)) {
|
if (!oldRoutes.contains(ri)) {
|
||||||
mHwInterface.addDownstreamPrefix(ifname, ri.getDestination().toString());
|
mHwInterface.addDownstream(ifname, ri.getDestination().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -639,7 +628,7 @@ public class OffloadController {
|
|||||||
|
|
||||||
for (RouteInfo route : lp.getRoutes()) {
|
for (RouteInfo route : lp.getRoutes()) {
|
||||||
if (shouldIgnoreDownstreamRoute(route)) continue;
|
if (shouldIgnoreDownstreamRoute(route)) continue;
|
||||||
mHwInterface.removeDownstreamPrefix(ifname, route.getDestination().toString());
|
mHwInterface.removeDownstream(ifname, route.getDestination().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,7 +757,7 @@ public class OffloadController {
|
|||||||
final boolean isStarted = started();
|
final boolean isStarted = started();
|
||||||
pw.println("Offload HALs " + (isStarted ? "started" : "not started"));
|
pw.println("Offload HALs " + (isStarted ? "started" : "not started"));
|
||||||
pw.println("Offload Control HAL version: "
|
pw.println("Offload Control HAL version: "
|
||||||
+ OffloadHardwareInterface.halVerToString(mControlHalVersion));
|
+ OffloadHardwareInterface.halVerToString(mOffloadHalVersion));
|
||||||
LinkProperties lp = mUpstreamLinkProperties;
|
LinkProperties lp = mUpstreamLinkProperties;
|
||||||
String upstream = (lp != null) ? lp.getInterfaceName() : null;
|
String upstream = (lp != null) ? lp.getInterfaceName() : null;
|
||||||
pw.println("Current upstream: " + upstream);
|
pw.println("Current upstream: " + upstream);
|
||||||
|
|||||||
@@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.hardware.tetheroffload.ForwardedStats;
|
||||||
|
import android.hardware.tetheroffload.IOffload;
|
||||||
|
import android.hardware.tetheroffload.ITetheringOffloadCallback;
|
||||||
|
import android.hardware.tetheroffload.NatTimeoutUpdate;
|
||||||
|
import android.hardware.tetheroffload.NetworkProtocol;
|
||||||
|
import android.hardware.tetheroffload.OffloadCallbackEvent;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import com.android.modules.utils.build.SdkLevel;
|
||||||
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of IOffloadHal which based on Stable AIDL interface
|
||||||
|
*/
|
||||||
|
public class OffloadHalAidlImpl implements IOffloadHal {
|
||||||
|
private static final String TAG = OffloadHalAidlImpl.class.getSimpleName();
|
||||||
|
private static final String HAL_INSTANCE_NAME = IOffload.DESCRIPTOR + "/default";
|
||||||
|
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final SharedLog mLog;
|
||||||
|
private final IOffload mIOffload;
|
||||||
|
@OffloadHardwareInterface.OffloadHalVersion
|
||||||
|
private final int mOffloadVersion;
|
||||||
|
|
||||||
|
private TetheringOffloadCallback mTetheringOffloadCallback;
|
||||||
|
|
||||||
|
public OffloadHalAidlImpl(int version, @NonNull IOffload offload, @NonNull Handler handler,
|
||||||
|
@NonNull SharedLog log) {
|
||||||
|
mOffloadVersion = version;
|
||||||
|
mIOffload = offload;
|
||||||
|
mHandler = handler;
|
||||||
|
mLog = log.forSubComponent(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Tetheroffload HAL. Provides bound netlink file descriptors for use in the
|
||||||
|
* management process.
|
||||||
|
*/
|
||||||
|
public boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2,
|
||||||
|
@NonNull OffloadHalCallback callback) {
|
||||||
|
final String methodStr = String.format("initOffload(%d, %d, %s)",
|
||||||
|
handle1.getFileDescriptor().getInt$(), handle2.getFileDescriptor().getInt$(),
|
||||||
|
(callback == null) ? "null"
|
||||||
|
: "0x" + Integer.toHexString(System.identityHashCode(callback)));
|
||||||
|
mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, callback, mLog);
|
||||||
|
try {
|
||||||
|
mIOffload.initOffload(
|
||||||
|
ParcelFileDescriptor.adoptFd(handle1.getFileDescriptor().getInt$()),
|
||||||
|
ParcelFileDescriptor.adoptFd(handle2.getFileDescriptor().getInt$()),
|
||||||
|
mTetheringOffloadCallback);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop the Tetheroffload HAL. */
|
||||||
|
public boolean stopOffload() {
|
||||||
|
final String methodStr = "stopOffload()";
|
||||||
|
try {
|
||||||
|
mIOffload.stopOffload();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTetheringOffloadCallback = null;
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get HAL interface version number. */
|
||||||
|
public int getVersion() {
|
||||||
|
return mOffloadVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get Tx/Rx usage from last query. */
|
||||||
|
public OffloadHardwareInterface.ForwardedStats getForwardedStats(@NonNull String upstream) {
|
||||||
|
ForwardedStats stats = new ForwardedStats();
|
||||||
|
final String methodStr = String.format("getForwardedStats(%s)", upstream);
|
||||||
|
try {
|
||||||
|
stats = mIOffload.getForwardedStats(upstream);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return new OffloadHardwareInterface.ForwardedStats(stats.rxBytes, stats.txBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set local prefixes to offload management process. */
|
||||||
|
public boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes) {
|
||||||
|
final String methodStr = String.format("setLocalPrefixes([%s])",
|
||||||
|
String.join(",", localPrefixes));
|
||||||
|
try {
|
||||||
|
mIOffload.setLocalPrefixes(localPrefixes.toArray(new String[localPrefixes.size()]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data limit value to offload management process.
|
||||||
|
* Method setDataLimit is deprecated in AIDL, so call setDataWarningAndLimit instead,
|
||||||
|
* with warningBytes set to its MAX_VALUE.
|
||||||
|
*/
|
||||||
|
public boolean setDataLimit(@NonNull String iface, long limit) {
|
||||||
|
final long warning = Long.MAX_VALUE;
|
||||||
|
final String methodStr = String.format("setDataLimit(%s, %d)", iface, limit);
|
||||||
|
try {
|
||||||
|
mIOffload.setDataWarningAndLimit(iface, warning, limit);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set data warning and limit value to offload management process. */
|
||||||
|
public boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit) {
|
||||||
|
final String methodStr =
|
||||||
|
String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit);
|
||||||
|
try {
|
||||||
|
mIOffload.setDataWarningAndLimit(iface, warning, limit);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set upstream parameters to offload management process. */
|
||||||
|
public boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr,
|
||||||
|
@NonNull String v4gateway, @NonNull ArrayList<String> v6gws) {
|
||||||
|
final String methodStr = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
|
||||||
|
iface, v4addr, v4gateway, String.join(",", v6gws));
|
||||||
|
try {
|
||||||
|
mIOffload.setUpstreamParameters(iface, v4addr, v4gateway,
|
||||||
|
v6gws.toArray(new String[v6gws.size()]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add downstream prefix to offload management process. */
|
||||||
|
public boolean addDownstream(@NonNull String ifname, @NonNull String prefix) {
|
||||||
|
final String methodStr = String.format("addDownstream(%s, %s)", ifname, prefix);
|
||||||
|
try {
|
||||||
|
mIOffload.addDownstream(ifname, prefix);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove downstream prefix from offload management process. */
|
||||||
|
public boolean removeDownstream(@NonNull String ifname, @NonNull String prefix) {
|
||||||
|
final String methodStr = String.format("removeDownstream(%s, %s)", ifname, prefix);
|
||||||
|
try {
|
||||||
|
mIOffload.removeDownstream(ifname, prefix);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logAndIgnoreException(e, methodStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mLog.i(methodStr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get {@link IOffloadHal} object from the AIDL service.
|
||||||
|
*
|
||||||
|
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
|
||||||
|
* @param log Log to be used by the repository.
|
||||||
|
*/
|
||||||
|
public static IOffloadHal getIOffloadHal(Handler handler, SharedLog log) {
|
||||||
|
// Tetheroffload AIDL interface is only supported after U.
|
||||||
|
if (!SdkLevel.isAtLeastU() || !ServiceManager.isDeclared(HAL_INSTANCE_NAME)) return null;
|
||||||
|
|
||||||
|
IOffload offload = IOffload.Stub.asInterface(
|
||||||
|
ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
|
||||||
|
if (offload == null) return null;
|
||||||
|
|
||||||
|
return new OffloadHalAidlImpl(OFFLOAD_HAL_VERSION_AIDL, offload, handler, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logAndIgnoreException(Exception e, final String methodStr) {
|
||||||
|
mLog.e(methodStr + " failed with " + e.getClass().getSimpleName() + ": ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
|
||||||
|
public final Handler handler;
|
||||||
|
public final OffloadHalCallback callback;
|
||||||
|
public final SharedLog log;
|
||||||
|
|
||||||
|
TetheringOffloadCallback(
|
||||||
|
Handler h, OffloadHalCallback cb, SharedLog sharedLog) {
|
||||||
|
handler = h;
|
||||||
|
callback = cb;
|
||||||
|
log = sharedLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOnEvent(int event) {
|
||||||
|
switch (event) {
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STARTED:
|
||||||
|
callback.onStarted();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
|
||||||
|
callback.onStoppedError();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
|
||||||
|
callback.onStoppedUnsupported();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
|
||||||
|
callback.onSupportAvailable();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
|
||||||
|
callback.onStoppedLimitReached();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_WARNING_REACHED:
|
||||||
|
callback.onWarningReached();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.e("Unsupported OffloadCallbackEvent: " + event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(int event) {
|
||||||
|
handler.post(() -> {
|
||||||
|
handleOnEvent(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTimeout(NatTimeoutUpdate params) {
|
||||||
|
handler.post(() -> {
|
||||||
|
callback.onNatTimeoutUpdate(
|
||||||
|
networkProtocolToOsConstant(params.proto),
|
||||||
|
params.src.addr, params.src.port,
|
||||||
|
params.dst.addr, params.dst.port);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInterfaceHash() {
|
||||||
|
return ITetheringOffloadCallback.HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInterfaceVersion() {
|
||||||
|
return ITetheringOffloadCallback.VERSION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int networkProtocolToOsConstant(int proto) {
|
||||||
|
switch (proto) {
|
||||||
|
case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
|
||||||
|
case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
|
||||||
|
default:
|
||||||
|
// The caller checks this value and will log an error. Just make
|
||||||
|
// sure it won't collide with valid OsConstants.IPPROTO_* values.
|
||||||
|
return -Math.abs(proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,436 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.halVerToString;
|
||||||
|
import static com.android.networkstack.tethering.util.TetheringUtils.uint16;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
||||||
|
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of IOffloadHal which based on HIDL interfaces
|
||||||
|
*/
|
||||||
|
public class OffloadHalHidlImpl implements IOffloadHal {
|
||||||
|
private static final String TAG = OffloadHalHidlImpl.class.getSimpleName();
|
||||||
|
private static final String YIELDS = " -> ";
|
||||||
|
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final SharedLog mLog;
|
||||||
|
private final IOffloadConfig mIOffloadConfig;
|
||||||
|
private final IOffloadControl mIOffloadControl;
|
||||||
|
@OffloadHardwareInterface.OffloadHalVersion
|
||||||
|
private final int mOffloadControlVersion;
|
||||||
|
|
||||||
|
private OffloadHalCallback mOffloadHalCallback;
|
||||||
|
private TetheringOffloadCallback mTetheringOffloadCallback;
|
||||||
|
|
||||||
|
public OffloadHalHidlImpl(int version, @NonNull IOffloadConfig config,
|
||||||
|
@NonNull IOffloadControl control, @NonNull Handler handler, @NonNull SharedLog log) {
|
||||||
|
mOffloadControlVersion = version;
|
||||||
|
mIOffloadConfig = config;
|
||||||
|
mIOffloadControl = control;
|
||||||
|
mHandler = handler;
|
||||||
|
mLog = log.forSubComponent(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Tetheroffload HAL. Provides bound netlink file descriptors for use in the
|
||||||
|
* management process.
|
||||||
|
*/
|
||||||
|
public boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2,
|
||||||
|
@NonNull OffloadHalCallback callback) {
|
||||||
|
final String logmsg = String.format("initOffload(%d, %d, %s)",
|
||||||
|
handle1.getFileDescriptor().getInt$(), handle2.getFileDescriptor().getInt$(),
|
||||||
|
(callback == null) ? "null"
|
||||||
|
: "0x" + Integer.toHexString(System.identityHashCode(callback)));
|
||||||
|
|
||||||
|
mOffloadHalCallback = callback;
|
||||||
|
mTetheringOffloadCallback = new TetheringOffloadCallback(
|
||||||
|
mHandler, mOffloadHalCallback, mLog, mOffloadControlVersion);
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadConfig.setHandles(handle1, handle2,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
mIOffloadControl.initOffload(
|
||||||
|
mTetheringOffloadCallback,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop the Tetheroffload HAL. */
|
||||||
|
public boolean stopOffload() {
|
||||||
|
try {
|
||||||
|
mIOffloadControl.stopOffload(
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
if (!success) mLog.e("stopOffload failed: " + errMsg);
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
mLog.e("failed to stopOffload: " + e);
|
||||||
|
}
|
||||||
|
mOffloadHalCallback = null;
|
||||||
|
mTetheringOffloadCallback = null;
|
||||||
|
mLog.log("stopOffload()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get HAL interface version number. */
|
||||||
|
public int getVersion() {
|
||||||
|
return mOffloadControlVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get Tx/Rx usage from last query. */
|
||||||
|
public ForwardedStats getForwardedStats(@NonNull String upstream) {
|
||||||
|
final String logmsg = String.format("getForwardedStats(%s)", upstream);
|
||||||
|
|
||||||
|
final ForwardedStats stats = new ForwardedStats();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.getForwardedStats(
|
||||||
|
upstream,
|
||||||
|
(long rxBytes, long txBytes) -> {
|
||||||
|
stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
|
||||||
|
stats.txBytes = (txBytes > 0) ? txBytes : 0;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set local prefixes to offload management process. */
|
||||||
|
public boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes) {
|
||||||
|
final String logmsg = String.format("setLocalPrefixes([%s])",
|
||||||
|
String.join(",", localPrefixes));
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.setLocalPrefixes(localPrefixes,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set data limit value to offload management process. */
|
||||||
|
public boolean setDataLimit(@NonNull String iface, long limit) {
|
||||||
|
|
||||||
|
final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.setDataLimit(
|
||||||
|
iface, limit,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set data warning and limit value to offload management process. */
|
||||||
|
public boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit) {
|
||||||
|
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"setDataWarningAndLimit is not supported below HAL V1.1");
|
||||||
|
}
|
||||||
|
final String logmsg =
|
||||||
|
String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit);
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControl)
|
||||||
|
.setDataWarningAndLimit(
|
||||||
|
iface, warning, limit,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set upstream parameters to offload management process. */
|
||||||
|
public boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr,
|
||||||
|
@NonNull String v4gateway, @NonNull ArrayList<String> v6gws) {
|
||||||
|
final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
|
||||||
|
iface, v4addr, v4gateway, String.join(",", v6gws));
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.setUpstreamParameters(
|
||||||
|
iface, v4addr, v4gateway, v6gws,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add downstream prefix to offload management process. */
|
||||||
|
public boolean addDownstream(@NonNull String ifname, @NonNull String prefix) {
|
||||||
|
final String logmsg = String.format("addDownstream(%s, %s)", ifname, prefix);
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.addDownstream(ifname, prefix,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove downstream prefix from offload management process. */
|
||||||
|
public boolean removeDownstream(@NonNull String ifname, @NonNull String prefix) {
|
||||||
|
final String logmsg = String.format("removeDownstream(%s, %s)", ifname, prefix);
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
mIOffloadControl.removeDownstream(ifname, prefix,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get {@link IOffloadHal} object from the HIDL service.
|
||||||
|
*
|
||||||
|
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
|
||||||
|
* @param log Log to be used by the repository.
|
||||||
|
*/
|
||||||
|
public static IOffloadHal getIOffloadHal(Handler handler, SharedLog log) {
|
||||||
|
IOffloadConfig config = null;
|
||||||
|
try {
|
||||||
|
config = IOffloadConfig.getService(true /*retry*/);
|
||||||
|
} catch (RemoteException | NoSuchElementException e) {
|
||||||
|
log.e("getIOffloadConfig error " + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOffloadControl control = null;
|
||||||
|
int version = OFFLOAD_HAL_VERSION_NONE;
|
||||||
|
try {
|
||||||
|
control = android.hardware.tetheroffload.control
|
||||||
|
.V1_1.IOffloadControl.getService(true /*retry*/);
|
||||||
|
version = OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// Unsupported by device.
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
log.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
|
}
|
||||||
|
if (control == null) {
|
||||||
|
try {
|
||||||
|
control = IOffloadControl.getService(true /*retry*/);
|
||||||
|
version = OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// Unsupported by device.
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
log.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == null || control == null) return null;
|
||||||
|
|
||||||
|
return new OffloadHalHidlImpl(version, config, control, handler, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void record(String msg, Throwable t) {
|
||||||
|
mLog.e(msg + YIELDS + "exception: " + t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void record(String msg, CbResults results) {
|
||||||
|
final String logmsg = msg + YIELDS + results;
|
||||||
|
if (!results.mSuccess) {
|
||||||
|
mLog.e(logmsg);
|
||||||
|
} else {
|
||||||
|
mLog.log(logmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
|
||||||
|
public final Handler handler;
|
||||||
|
public final OffloadHalCallback callback;
|
||||||
|
public final SharedLog log;
|
||||||
|
private final int mOffloadControlVersion;
|
||||||
|
|
||||||
|
TetheringOffloadCallback(
|
||||||
|
Handler h, OffloadHalCallback cb, SharedLog sharedLog, int offloadControlVersion) {
|
||||||
|
handler = h;
|
||||||
|
callback = cb;
|
||||||
|
log = sharedLog;
|
||||||
|
this.mOffloadControlVersion = offloadControlVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOnEvent(int event) {
|
||||||
|
switch (event) {
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STARTED:
|
||||||
|
callback.onStarted();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
|
||||||
|
callback.onStoppedError();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
|
||||||
|
callback.onStoppedUnsupported();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
|
||||||
|
callback.onSupportAvailable();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
|
||||||
|
callback.onStoppedLimitReached();
|
||||||
|
break;
|
||||||
|
case android.hardware.tetheroffload.control
|
||||||
|
.V1_1.OffloadCallbackEvent.OFFLOAD_WARNING_REACHED:
|
||||||
|
callback.onWarningReached();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.e("Unsupported OffloadCallbackEvent: " + event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(int event) {
|
||||||
|
// The implementation should never call onEvent()) if the event is already reported
|
||||||
|
// through newer callback.
|
||||||
|
if (mOffloadControlVersion > OFFLOAD_HAL_VERSION_HIDL_1_0) {
|
||||||
|
Log.wtf(TAG, "onEvent(" + event + ") fired on HAL "
|
||||||
|
+ halVerToString(mOffloadControlVersion));
|
||||||
|
}
|
||||||
|
handler.post(() -> {
|
||||||
|
handleOnEvent(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent_1_1(int event) {
|
||||||
|
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
|
Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL "
|
||||||
|
+ halVerToString(mOffloadControlVersion));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.post(() -> {
|
||||||
|
handleOnEvent(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTimeout(NatTimeoutUpdate params) {
|
||||||
|
handler.post(() -> {
|
||||||
|
callback.onNatTimeoutUpdate(
|
||||||
|
networkProtocolToOsConstant(params.proto),
|
||||||
|
params.src.addr, uint16(params.src.port),
|
||||||
|
params.dst.addr, uint16(params.dst.port));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int networkProtocolToOsConstant(int proto) {
|
||||||
|
switch (proto) {
|
||||||
|
case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
|
||||||
|
case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
|
||||||
|
default:
|
||||||
|
// The caller checks this value and will log an error. Just make
|
||||||
|
// sure it won't collide with valid OsConstants.IPPROTO_* values.
|
||||||
|
return -Math.abs(proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CbResults {
|
||||||
|
boolean mSuccess;
|
||||||
|
String mErrMsg;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (mSuccess) {
|
||||||
|
return "ok";
|
||||||
|
} else {
|
||||||
|
return "fail: " + mErrMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,25 +18,15 @@ package com.android.networkstack.tethering;
|
|||||||
|
|
||||||
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
||||||
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||||
import static com.android.networkstack.tethering.util.TetheringUtils.uint16;
|
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
|
||||||
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
|
||||||
import android.net.util.SocketUtils;
|
import android.net.util.SocketUtils;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.NativeHandle;
|
import android.os.NativeHandle;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.net.module.util.SharedLog;
|
import com.android.net.module.util.SharedLog;
|
||||||
@@ -54,8 +44,6 @@ import java.net.SocketException;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture tethering dependencies, for injection.
|
* Capture tethering dependencies, for injection.
|
||||||
@@ -86,43 +74,43 @@ public class OffloadHardwareInterface {
|
|||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final SharedLog mLog;
|
private final SharedLog mLog;
|
||||||
private final Dependencies mDeps;
|
private final Dependencies mDeps;
|
||||||
private IOffloadControl mOffloadControl;
|
private IOffloadHal mIOffload;
|
||||||
|
|
||||||
// TODO: Use major-minor version control to prevent from defining new constants.
|
// 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_NONE = 0;
|
||||||
static final int OFFLOAD_HAL_VERSION_1_0 = 1;
|
static final int OFFLOAD_HAL_VERSION_HIDL_1_0 = 1;
|
||||||
static final int OFFLOAD_HAL_VERSION_1_1 = 2;
|
static final int OFFLOAD_HAL_VERSION_HIDL_1_1 = 2;
|
||||||
|
static final int OFFLOAD_HAL_VERSION_AIDL = 3;
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef(prefix = "OFFLOAD_HAL_VERSION_", value = {
|
@IntDef(prefix = "OFFLOAD_HAL_VERSION_", value = {
|
||||||
OFFLOAD_HAL_VERSION_NONE,
|
OFFLOAD_HAL_VERSION_NONE,
|
||||||
OFFLOAD_HAL_VERSION_1_0,
|
OFFLOAD_HAL_VERSION_HIDL_1_0,
|
||||||
OFFLOAD_HAL_VERSION_1_1
|
OFFLOAD_HAL_VERSION_HIDL_1_1,
|
||||||
|
OFFLOAD_HAL_VERSION_AIDL,
|
||||||
})
|
})
|
||||||
public @interface OffloadHalVersion {}
|
public @interface OffloadHalVersion {}
|
||||||
@OffloadHalVersion
|
|
||||||
private int mOffloadControlVersion = OFFLOAD_HAL_VERSION_NONE;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
static String halVerToString(int version) {
|
static String halVerToString(int version) {
|
||||||
switch(version) {
|
switch(version) {
|
||||||
case OFFLOAD_HAL_VERSION_1_0:
|
case OFFLOAD_HAL_VERSION_HIDL_1_0:
|
||||||
return "1.0";
|
return "HIDL 1.0";
|
||||||
case OFFLOAD_HAL_VERSION_1_1:
|
case OFFLOAD_HAL_VERSION_HIDL_1_1:
|
||||||
return "1.1";
|
return "HIDL 1.1";
|
||||||
|
case OFFLOAD_HAL_VERSION_AIDL:
|
||||||
|
return "AIDL";
|
||||||
case OFFLOAD_HAL_VERSION_NONE:
|
case OFFLOAD_HAL_VERSION_NONE:
|
||||||
return "None";
|
return "None";
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported version int " + version);
|
throw new IllegalArgumentException("Unsupported version int " + version);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TetheringOffloadCallback mTetheringOffloadCallback;
|
private OffloadHalCallback mOffloadHalCallback;
|
||||||
private ControlCallback mControlCallback;
|
|
||||||
|
|
||||||
/** The callback to notify status of offload management process. */
|
/** The callback to notify status of offload management process. */
|
||||||
public static class ControlCallback {
|
public static class OffloadHalCallback {
|
||||||
/** Offload started. */
|
/** Offload started. */
|
||||||
public void onStarted() {}
|
public void onStarted() {}
|
||||||
/**
|
/**
|
||||||
@@ -179,7 +167,7 @@ public class OffloadHardwareInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public OffloadHardwareInterface(Handler h, SharedLog log) {
|
public OffloadHardwareInterface(Handler h, SharedLog log) {
|
||||||
this(h, log, new Dependencies(log));
|
this(h, log, new Dependencies(h, log));
|
||||||
}
|
}
|
||||||
|
|
||||||
OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
|
OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
|
||||||
@@ -190,45 +178,21 @@ public class OffloadHardwareInterface {
|
|||||||
|
|
||||||
/** Capture OffloadHardwareInterface dependencies, for injection. */
|
/** Capture OffloadHardwareInterface dependencies, for injection. */
|
||||||
static class Dependencies {
|
static class Dependencies {
|
||||||
|
private final Handler mHandler;
|
||||||
private final SharedLog mLog;
|
private final SharedLog mLog;
|
||||||
|
|
||||||
Dependencies(SharedLog log) {
|
Dependencies(Handler handler, SharedLog log) {
|
||||||
|
mHandler = handler;
|
||||||
mLog = log;
|
mLog = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOffloadConfig getOffloadConfig() {
|
public IOffloadHal getOffload() {
|
||||||
try {
|
// Prefer AIDL implementation if its service is declared.
|
||||||
return IOffloadConfig.getService(true /*retry*/);
|
IOffloadHal hal = OffloadHalAidlImpl.getIOffloadHal(mHandler, mLog);
|
||||||
} catch (RemoteException | NoSuchElementException e) {
|
|
||||||
mLog.e("getIOffloadConfig error " + e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Pair<IOffloadControl, Integer> getOffloadControl() {
|
|
||||||
IOffloadControl hal = null;
|
|
||||||
int version = OFFLOAD_HAL_VERSION_NONE;
|
|
||||||
try {
|
|
||||||
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) {
|
if (hal == null) {
|
||||||
try {
|
hal = OffloadHalHidlImpl.getIOffloadHal(mHandler, mLog);
|
||||||
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<IOffloadControl, Integer>(hal, version);
|
return hal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeHandle createConntrackSocket(final int groups) {
|
public NativeHandle createConntrackSocket(final int groups) {
|
||||||
@@ -273,56 +237,6 @@ public class OffloadHardwareInterface {
|
|||||||
return DEFAULT_TETHER_OFFLOAD_DISABLED;
|
return DEFAULT_TETHER_OFFLOAD_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Offload management process need to know conntrack rules to support NAT, but it may not have
|
|
||||||
* permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
|
|
||||||
* share them with offload management process.
|
|
||||||
*/
|
|
||||||
public boolean initOffloadConfig() {
|
|
||||||
final IOffloadConfig offloadConfig = mDeps.getOffloadConfig();
|
|
||||||
if (offloadConfig == null) {
|
|
||||||
mLog.e("Could not find IOffloadConfig service");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Per the IConfigOffload definition:
|
|
||||||
//
|
|
||||||
// h1 provides a file descriptor bound to the following netlink groups
|
|
||||||
// (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
|
|
||||||
//
|
|
||||||
// h2 provides a file descriptor bound to the following netlink groups
|
|
||||||
// (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
|
|
||||||
final NativeHandle h1 = mDeps.createConntrackSocket(
|
|
||||||
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
|
||||||
if (h1 == null) return false;
|
|
||||||
|
|
||||||
requestSocketDump(h1);
|
|
||||||
|
|
||||||
final NativeHandle h2 = mDeps.createConntrackSocket(
|
|
||||||
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
|
|
||||||
if (h2 == null) {
|
|
||||||
closeFdInNativeHandle(h1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
offloadConfig.setHandles(h1, h2,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record("initOffloadConfig, setHandles fail", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Explicitly close FDs.
|
|
||||||
closeFdInNativeHandle(h1);
|
|
||||||
closeFdInNativeHandle(h2);
|
|
||||||
|
|
||||||
record("initOffloadConfig, setHandles results:", results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
|
void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
|
||||||
final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||||
@@ -355,165 +269,107 @@ public class OffloadHardwareInterface {
|
|||||||
(short) (NLM_F_REQUEST | NLM_F_DUMP));
|
(short) (NLM_F_REQUEST | NLM_F_DUMP));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeFdInNativeHandle(final NativeHandle h) {
|
private void maybeCloseFdInNativeHandles(final NativeHandle... handles) {
|
||||||
try {
|
for (NativeHandle h : handles) {
|
||||||
h.close();
|
if (h == null) continue;
|
||||||
} catch (IOException | IllegalStateException e) {
|
try {
|
||||||
// IllegalStateException means fd is already closed, do nothing here.
|
h.close();
|
||||||
// Also nothing we can do if IOException.
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
// IllegalStateException means fd is already closed, do nothing here.
|
||||||
|
// Also nothing we can do if IOException.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int initWithHandles(NativeHandle h1, NativeHandle h2) {
|
||||||
|
if (h1 == null || h2 == null) {
|
||||||
|
mLog.e("Failed to create socket.");
|
||||||
|
return OFFLOAD_HAL_VERSION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestSocketDump(h1);
|
||||||
|
if (!mIOffload.initOffload(h1, h2, mOffloadHalCallback)) {
|
||||||
|
mIOffload.stopOffload();
|
||||||
|
mLog.e("Failed to initialize offload.");
|
||||||
|
return OFFLOAD_HAL_VERSION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mIOffload.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the tethering offload HAL.
|
* Initialize the tethering offload HAL.
|
||||||
*
|
*
|
||||||
* @return one of {@code OFFLOAD_HAL_VERSION_*} represents the HAL version, or
|
* @return one of {@code OFFLOAD_HAL_VERSION_*} represents the HAL version, or
|
||||||
* {@link #OFFLOAD_HAL_VERSION_NONE} if failed.
|
* {@link #OFFLOAD_HAL_VERSION_NONE} if failed.
|
||||||
*/
|
*/
|
||||||
public int initOffloadControl(ControlCallback controlCb) {
|
public int initOffload(OffloadHalCallback offloadCb) {
|
||||||
mControlCallback = controlCb;
|
if (mIOffload == null) {
|
||||||
|
mIOffload = mDeps.getOffload();
|
||||||
if (mOffloadControl == null) {
|
if (mIOffload == null) {
|
||||||
final Pair<IOffloadControl, Integer> halAndVersion = mDeps.getOffloadControl();
|
mLog.e("No tethering offload HAL service found.");
|
||||||
mOffloadControl = halAndVersion.first;
|
|
||||||
mOffloadControlVersion = halAndVersion.second;
|
|
||||||
if (mOffloadControl == null) {
|
|
||||||
mLog.e("tethering IOffloadControl.getService() returned null");
|
|
||||||
return OFFLOAD_HAL_VERSION_NONE;
|
return OFFLOAD_HAL_VERSION_NONE;
|
||||||
}
|
}
|
||||||
mLog.i("tethering offload control version "
|
mLog.i("Tethering offload version "
|
||||||
+ halVerToString(mOffloadControlVersion) + " is supported.");
|
+ halVerToString(mIOffload.getVersion()) + " is supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String logmsg = String.format("initOffloadControl(%s)",
|
// Per the IOffload definition:
|
||||||
(controlCb == null) ? "null"
|
//
|
||||||
: "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
|
// h1 provides a file descriptor bound to the following netlink groups
|
||||||
|
// (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
|
||||||
|
//
|
||||||
|
// h2 provides a file descriptor bound to the following netlink groups
|
||||||
|
// (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
|
||||||
|
final NativeHandle h1 = mDeps.createConntrackSocket(
|
||||||
|
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
|
||||||
|
final NativeHandle h2 = mDeps.createConntrackSocket(
|
||||||
|
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
|
||||||
|
|
||||||
mTetheringOffloadCallback = new TetheringOffloadCallback(
|
mOffloadHalCallback = offloadCb;
|
||||||
mHandler, mControlCallback, mLog, mOffloadControlVersion);
|
final int version = initWithHandles(h1, h2);
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
// Explicitly close FDs for HIDL. AIDL will pass the original FDs to the service,
|
||||||
mOffloadControl.initOffload(
|
// they shouldn't be closed here.
|
||||||
mTetheringOffloadCallback,
|
if (version < OFFLOAD_HAL_VERSION_AIDL) {
|
||||||
(boolean success, String errMsg) -> {
|
maybeCloseFdInNativeHandles(h1, h2);
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return OFFLOAD_HAL_VERSION_NONE;
|
|
||||||
}
|
}
|
||||||
|
return version;
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess ? mOffloadControlVersion : OFFLOAD_HAL_VERSION_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stop IOffloadControl. */
|
/** Stop the tethering offload HAL. */
|
||||||
public void stopOffloadControl() {
|
public void stopOffload() {
|
||||||
if (mOffloadControl != null) {
|
if (mIOffload != null) {
|
||||||
try {
|
if (!mIOffload.stopOffload()) {
|
||||||
mOffloadControl.stopOffload(
|
mLog.e("Failed to stop offload.");
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
if (!success) mLog.e("stopOffload failed: " + errMsg);
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
mLog.e("failed to stopOffload: " + e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mOffloadControl = null;
|
mIOffload = null;
|
||||||
mTetheringOffloadCallback = null;
|
mOffloadHalCallback = null;
|
||||||
mControlCallback = null;
|
|
||||||
mLog.log("stopOffloadControl()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get Tx/Rx usage from last query. */
|
/** Get Tx/Rx usage from last query. */
|
||||||
public ForwardedStats getForwardedStats(String upstream) {
|
public ForwardedStats getForwardedStats(String upstream) {
|
||||||
final String logmsg = String.format("getForwardedStats(%s)", upstream);
|
return mIOffload.getForwardedStats(upstream);
|
||||||
|
|
||||||
final ForwardedStats stats = new ForwardedStats();
|
|
||||||
try {
|
|
||||||
mOffloadControl.getForwardedStats(
|
|
||||||
upstream,
|
|
||||||
(long rxBytes, long txBytes) -> {
|
|
||||||
stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
|
|
||||||
stats.txBytes = (txBytes > 0) ? txBytes : 0;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set local prefixes to offload management process. */
|
/** Set local prefixes to offload management process. */
|
||||||
public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
|
public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
|
||||||
final String logmsg = String.format("setLocalPrefixes([%s])",
|
return mIOffload.setLocalPrefixes(localPrefixes);
|
||||||
String.join(",", localPrefixes));
|
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
mOffloadControl.setLocalPrefixes(localPrefixes,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set data limit value to offload management process. */
|
/** Set data limit value to offload management process. */
|
||||||
public boolean setDataLimit(String iface, long limit) {
|
public boolean setDataLimit(String iface, long limit) {
|
||||||
|
return mIOffload.setDataLimit(iface, limit);
|
||||||
final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
|
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
mOffloadControl.setDataLimit(
|
|
||||||
iface, limit,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set data warning and limit value to offload management process. */
|
/** Set data warning and limit value to offload management process. */
|
||||||
public boolean setDataWarningAndLimit(String iface, long warning, long limit) {
|
public boolean setDataWarningAndLimit(String iface, long warning, long limit) {
|
||||||
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) {
|
if (mIOffload.getVersion() < OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
throw new IllegalArgumentException(
|
throw new UnsupportedOperationException(
|
||||||
"setDataWarningAndLimit is not supported below HAL V1.1");
|
"setDataWarningAndLimit is not supported below HAL V1.1");
|
||||||
}
|
}
|
||||||
final String logmsg =
|
return mIOffload.setDataWarningAndLimit(iface, warning, limit);
|
||||||
String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit);
|
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mOffloadControl)
|
|
||||||
.setDataWarningAndLimit(
|
|
||||||
iface, warning, limit,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set upstream parameters to offload management process. */
|
/** Set upstream parameters to offload management process. */
|
||||||
@@ -523,178 +379,16 @@ public class OffloadHardwareInterface {
|
|||||||
v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
|
v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
|
||||||
v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
|
v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
|
||||||
v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
|
v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
|
||||||
|
return mIOffload.setUpstreamParameters(iface, v4addr, v4gateway, v6gws);
|
||||||
final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
|
|
||||||
iface, v4addr, v4gateway, String.join(",", v6gws));
|
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
mOffloadControl.setUpstreamParameters(
|
|
||||||
iface, v4addr, v4gateway, v6gws,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add downstream prefix to offload management process. */
|
/** Add downstream prefix to offload management process. */
|
||||||
public boolean addDownstreamPrefix(String ifname, String prefix) {
|
public boolean addDownstream(String ifname, String prefix) {
|
||||||
final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
|
return mIOffload.addDownstream(ifname, prefix);
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
mOffloadControl.addDownstream(ifname, prefix,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove downstream prefix from offload management process. */
|
/** Remove downstream prefix from offload management process. */
|
||||||
public boolean removeDownstreamPrefix(String ifname, String prefix) {
|
public boolean removeDownstream(String ifname, String prefix) {
|
||||||
final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
|
return mIOffload.removeDownstream(ifname, prefix);
|
||||||
|
|
||||||
final CbResults results = new CbResults();
|
|
||||||
try {
|
|
||||||
mOffloadControl.removeDownstream(ifname, prefix,
|
|
||||||
(boolean success, String errMsg) -> {
|
|
||||||
results.mSuccess = success;
|
|
||||||
results.mErrMsg = errMsg;
|
|
||||||
});
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
record(logmsg, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
record(logmsg, results);
|
|
||||||
return results.mSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void record(String msg, Throwable t) {
|
|
||||||
mLog.e(msg + YIELDS + "exception: " + t);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void record(String msg, CbResults results) {
|
|
||||||
final String logmsg = msg + YIELDS + results;
|
|
||||||
if (!results.mSuccess) {
|
|
||||||
mLog.e(logmsg);
|
|
||||||
} else {
|
|
||||||
mLog.log(logmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
|
|
||||||
public final Handler handler;
|
|
||||||
public final ControlCallback controlCb;
|
|
||||||
public final SharedLog log;
|
|
||||||
private final int mOffloadControlVersion;
|
|
||||||
|
|
||||||
TetheringOffloadCallback(
|
|
||||||
Handler h, ControlCallback cb, SharedLog sharedLog, int offloadControlVersion) {
|
|
||||||
handler = h;
|
|
||||||
controlCb = cb;
|
|
||||||
log = sharedLog;
|
|
||||||
this.mOffloadControlVersion = offloadControlVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleOnEvent(int event) {
|
|
||||||
switch (event) {
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_STARTED:
|
|
||||||
controlCb.onStarted();
|
|
||||||
break;
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
|
|
||||||
controlCb.onStoppedError();
|
|
||||||
break;
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
|
|
||||||
controlCb.onStoppedUnsupported();
|
|
||||||
break;
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
|
|
||||||
controlCb.onSupportAvailable();
|
|
||||||
break;
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
|
|
||||||
controlCb.onStoppedLimitReached();
|
|
||||||
break;
|
|
||||||
case android.hardware.tetheroffload.control
|
|
||||||
.V1_1.OffloadCallbackEvent.OFFLOAD_WARNING_REACHED:
|
|
||||||
controlCb.onWarningReached();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log.e("Unsupported OffloadCallbackEvent: " + event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(int event) {
|
|
||||||
// The implementation should never call onEvent()) if the event is already reported
|
|
||||||
// through newer callback.
|
|
||||||
if (mOffloadControlVersion > OFFLOAD_HAL_VERSION_1_0) {
|
|
||||||
Log.wtf(TAG, "onEvent(" + event + ") fired on HAL "
|
|
||||||
+ halVerToString(mOffloadControlVersion));
|
|
||||||
}
|
|
||||||
handler.post(() -> {
|
|
||||||
handleOnEvent(event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent_1_1(int event) {
|
|
||||||
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) {
|
|
||||||
Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL "
|
|
||||||
+ halVerToString(mOffloadControlVersion));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler.post(() -> {
|
|
||||||
handleOnEvent(event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTimeout(NatTimeoutUpdate params) {
|
|
||||||
handler.post(() -> {
|
|
||||||
controlCb.onNatTimeoutUpdate(
|
|
||||||
networkProtocolToOsConstant(params.proto),
|
|
||||||
params.src.addr, uint16(params.src.port),
|
|
||||||
params.dst.addr, uint16(params.dst.port));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int networkProtocolToOsConstant(int proto) {
|
|
||||||
switch (proto) {
|
|
||||||
case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
|
|
||||||
case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
|
|
||||||
default:
|
|
||||||
// The caller checks this value and will log an error. Just make
|
|
||||||
// sure it won't collide with valid OsContants.IPPROTO_* values.
|
|
||||||
return -Math.abs(proto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CbResults {
|
|
||||||
boolean mSuccess;
|
|
||||||
String mErrMsg;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
if (mSuccess) {
|
|
||||||
return "ok";
|
|
||||||
} else {
|
|
||||||
return "fail: " + mErrMsg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class ConntrackSocketTest {
|
|||||||
// Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
|
// Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
|
||||||
mDeps = new OffloadHardwareInterface.Dependencies(mLog);
|
mDeps = new OffloadHardwareInterface.Dependencies(mHandler, mLog);
|
||||||
mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps);
|
mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
|
|||||||
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE;
|
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.OffloadController.StatsType.STATS_PER_UID;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
|
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_HIDL_1_0;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
|
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.assertContainsAll;
|
||||||
import static com.android.testutils.MiscAsserts.assertThrows;
|
import static com.android.testutils.MiscAsserts.assertThrows;
|
||||||
@@ -79,6 +79,7 @@ import androidx.test.runner.AndroidJUnit4;
|
|||||||
|
|
||||||
import com.android.internal.util.test.FakeSettingsProvider;
|
import com.android.internal.util.test.FakeSettingsProvider;
|
||||||
import com.android.net.module.util.SharedLog;
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
import com.android.testutils.DevSdkIgnoreRule;
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
import com.android.testutils.TestableNetworkStatsProviderCbBinder;
|
import com.android.testutils.TestableNetworkStatsProviderCbBinder;
|
||||||
@@ -125,8 +126,8 @@ public class OffloadControllerTest {
|
|||||||
private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider;
|
private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider;
|
||||||
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
|
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
|
||||||
ArgumentCaptor.forClass(ArrayList.class);
|
ArgumentCaptor.forClass(ArrayList.class);
|
||||||
private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
|
private final ArgumentCaptor<OffloadHalCallback> mOffloadHalCallbackCaptor =
|
||||||
ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
|
ArgumentCaptor.forClass(OffloadHalCallback.class);
|
||||||
private MockContentResolver mContentResolver;
|
private MockContentResolver mContentResolver;
|
||||||
private final TestLooper mTestLooper = new TestLooper();
|
private final TestLooper mTestLooper = new TestLooper();
|
||||||
private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() {
|
private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() {
|
||||||
@@ -151,10 +152,9 @@ public class OffloadControllerTest {
|
|||||||
FakeSettingsProvider.clearSettingsProvider();
|
FakeSettingsProvider.clearSettingsProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupFunctioningHardwareInterface(int controlVersion) {
|
private void setupFunctioningHardwareInterface(int offloadHalVersion) {
|
||||||
when(mHardware.initOffloadConfig()).thenReturn(true);
|
when(mHardware.initOffload(mOffloadHalCallbackCaptor.capture()))
|
||||||
when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
|
.thenReturn(offloadHalVersion);
|
||||||
.thenReturn(controlVersion);
|
|
||||||
when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true);
|
when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true);
|
||||||
when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
|
when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
|
||||||
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
|
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
|
||||||
@@ -192,9 +192,9 @@ public class OffloadControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testStartStop() throws Exception {
|
public void testStartStop() throws Exception {
|
||||||
stopOffloadController(
|
stopOffloadController(
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/));
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/));
|
||||||
stopOffloadController(
|
stopOffloadController(
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/));
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -206,9 +206,8 @@ public class OffloadControllerTest {
|
|||||||
|
|
||||||
final InOrder inOrder = inOrder(mHardware);
|
final InOrder inOrder = inOrder(mHardware);
|
||||||
inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
|
inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
|
||||||
inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffloadConfig();
|
inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffload(
|
||||||
inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffloadControl(
|
any(OffloadHalCallback.class));
|
||||||
any(OffloadHardwareInterface.ControlCallback.class));
|
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
// Clear counters only instead of whole mock to preserve the mocking setup.
|
// Clear counters only instead of whole mock to preserve the mocking setup.
|
||||||
clearInvocations(mHardware);
|
clearInvocations(mHardware);
|
||||||
@@ -218,7 +217,7 @@ public class OffloadControllerTest {
|
|||||||
private void stopOffloadController(final OffloadController offload) throws Exception {
|
private void stopOffloadController(final OffloadController offload) throws Exception {
|
||||||
final InOrder inOrder = inOrder(mHardware);
|
final InOrder inOrder = inOrder(mHardware);
|
||||||
offload.stop();
|
offload.stop();
|
||||||
inOrder.verify(mHardware, times(1)).stopOffloadControl();
|
inOrder.verify(mHardware, times(1)).stopOffload();
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
reset(mHardware);
|
reset(mHardware);
|
||||||
}
|
}
|
||||||
@@ -228,7 +227,7 @@ public class OffloadControllerTest {
|
|||||||
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
|
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
|
||||||
assertThrows(SettingNotFoundException.class, () ->
|
assertThrows(SettingNotFoundException.class, () ->
|
||||||
Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
|
Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -236,26 +235,26 @@ public class OffloadControllerTest {
|
|||||||
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
|
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
|
||||||
assertThrows(SettingNotFoundException.class, () ->
|
assertThrows(SettingNotFoundException.class, () ->
|
||||||
Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
|
Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSettingsAllowsStart() throws Exception {
|
public void testSettingsAllowsStart() throws Exception {
|
||||||
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
|
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSettingsDisablesStart() throws Exception {
|
public void testSettingsDisablesStart() throws Exception {
|
||||||
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
|
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetUpstreamLinkPropertiesWorking() throws Exception {
|
public void testSetUpstreamLinkPropertiesWorking() throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
// In reality, the UpstreamNetworkMonitor would have passed down to us
|
// In reality, the UpstreamNetworkMonitor would have passed down to us
|
||||||
// a covering set of local prefixes representing a minimum essential
|
// a covering set of local prefixes representing a minimum essential
|
||||||
@@ -426,7 +425,7 @@ public class OffloadControllerTest {
|
|||||||
public void testGetForwardedStats() throws Exception {
|
public void testGetForwardedStats() throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
final String ethernetIface = "eth1";
|
final String ethernetIface = "eth1";
|
||||||
final String mobileIface = "rmnet_data0";
|
final String mobileIface = "rmnet_data0";
|
||||||
@@ -521,11 +520,11 @@ public class OffloadControllerTest {
|
|||||||
// Verify the OffloadController is called by R framework, where the framework doesn't send
|
// Verify the OffloadController is called by R framework, where the framework doesn't send
|
||||||
// warning.
|
// warning.
|
||||||
// R only uses HAL 1.0.
|
// R only uses HAL 1.0.
|
||||||
checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_0);
|
checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
// Verify the OffloadController is called by S+ framework, where the framework sends
|
// Verify the OffloadController is called by S+ framework, where the framework sends
|
||||||
// warning along with limit.
|
// warning along with limit.
|
||||||
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_0);
|
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_1);
|
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion)
|
private void checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion)
|
||||||
@@ -550,7 +549,7 @@ public class OffloadControllerTest {
|
|||||||
when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
|
when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
// Applying an interface sends the initial quota to the hardware.
|
// Applying an interface sends the initial quota to the hardware.
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
|
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
|
||||||
Long.MAX_VALUE);
|
Long.MAX_VALUE);
|
||||||
} else {
|
} else {
|
||||||
@@ -576,7 +575,7 @@ public class OffloadControllerTest {
|
|||||||
mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit);
|
mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit);
|
||||||
}
|
}
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
|
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
|
||||||
ethernetLimit);
|
ethernetLimit);
|
||||||
} else {
|
} else {
|
||||||
@@ -591,7 +590,7 @@ public class OffloadControllerTest {
|
|||||||
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit);
|
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit);
|
||||||
}
|
}
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(),
|
inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(),
|
||||||
anyLong());
|
anyLong());
|
||||||
} else {
|
} else {
|
||||||
@@ -603,7 +602,7 @@ public class OffloadControllerTest {
|
|||||||
lp.setInterfaceName(mobileIface);
|
lp.setInterfaceName(mobileIface);
|
||||||
offload.setUpstreamLinkProperties(lp);
|
offload.setUpstreamLinkProperties(lp);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface,
|
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface,
|
||||||
isProviderSetWarning ? mobileWarning : Long.MAX_VALUE,
|
isProviderSetWarning ? mobileWarning : Long.MAX_VALUE,
|
||||||
mobileLimit);
|
mobileLimit);
|
||||||
@@ -620,7 +619,7 @@ public class OffloadControllerTest {
|
|||||||
mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED);
|
mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED);
|
||||||
}
|
}
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, Long.MAX_VALUE,
|
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, Long.MAX_VALUE,
|
||||||
Long.MAX_VALUE);
|
Long.MAX_VALUE);
|
||||||
} else {
|
} else {
|
||||||
@@ -655,15 +654,15 @@ public class OffloadControllerTest {
|
|||||||
}
|
}
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
inOrder.verify(mHardware).getForwardedStats(ethernetIface);
|
inOrder.verify(mHardware).getForwardedStats(ethernetIface);
|
||||||
inOrder.verify(mHardware).stopOffloadControl();
|
inOrder.verify(mHardware).stopOffload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDataWarningAndLimitCallback_LimitReached() throws Exception {
|
public void testDataWarningAndLimitCallback_LimitReached() throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
|
final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue();
|
||||||
callback.onStoppedLimitReached();
|
callback.onStoppedLimitReached();
|
||||||
mTetherStatsProviderCb.expectNotifyStatsUpdated();
|
mTetherStatsProviderCb.expectNotifyStatsUpdated();
|
||||||
|
|
||||||
@@ -679,8 +678,8 @@ public class OffloadControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
@IgnoreUpTo(Build.VERSION_CODES.R) // HAL 1.1 is only supported from S
|
@IgnoreUpTo(Build.VERSION_CODES.R) // HAL 1.1 is only supported from S
|
||||||
public void testDataWarningAndLimitCallback_WarningReached() throws Exception {
|
public void testDataWarningAndLimitCallback_WarningReached() throws Exception {
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/);
|
||||||
final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
|
final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue();
|
||||||
callback.onWarningReached();
|
callback.onWarningReached();
|
||||||
mTetherStatsProviderCb.expectNotifyStatsUpdated();
|
mTetherStatsProviderCb.expectNotifyStatsUpdated();
|
||||||
|
|
||||||
@@ -695,7 +694,7 @@ public class OffloadControllerTest {
|
|||||||
public void testAddRemoveDownstreams() throws Exception {
|
public void testAddRemoveDownstreams() throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
final InOrder inOrder = inOrder(mHardware);
|
final InOrder inOrder = inOrder(mHardware);
|
||||||
|
|
||||||
// Tethering makes several calls to setLocalPrefixes() before add/remove
|
// Tethering makes several calls to setLocalPrefixes() before add/remove
|
||||||
@@ -710,14 +709,14 @@ public class OffloadControllerTest {
|
|||||||
usbLinkProperties.addRoute(
|
usbLinkProperties.addRoute(
|
||||||
new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST));
|
new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST));
|
||||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX);
|
inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, USB_PREFIX);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// [2] Routes for IPv6 link-local prefixes should never be added.
|
// [2] Routes for IPv6 link-local prefixes should never be added.
|
||||||
usbLinkProperties.addRoute(
|
usbLinkProperties.addRoute(
|
||||||
new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST));
|
new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST));
|
||||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||||
inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
|
inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString());
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// [3] Add an IPv6 prefix for good measure. Only new offload-able
|
// [3] Add an IPv6 prefix for good measure. Only new offload-able
|
||||||
@@ -726,14 +725,14 @@ public class OffloadControllerTest {
|
|||||||
usbLinkProperties.addRoute(
|
usbLinkProperties.addRoute(
|
||||||
new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST));
|
new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST));
|
||||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
|
inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DOC_PREFIX);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// [4] Adding addresses doesn't affect notifyDownstreamLinkProperties().
|
// [4] Adding addresses doesn't affect notifyDownstreamLinkProperties().
|
||||||
// The address is passed in by a separate setLocalPrefixes() invocation.
|
// The address is passed in by a separate setLocalPrefixes() invocation.
|
||||||
usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64"));
|
usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64"));
|
||||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||||
inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
|
inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString());
|
||||||
|
|
||||||
// [5] Differences in local routes are converted into addDownstream()
|
// [5] Differences in local routes are converted into addDownstream()
|
||||||
// and removeDownstream() invocations accordingly.
|
// and removeDownstream() invocations accordingly.
|
||||||
@@ -742,8 +741,8 @@ public class OffloadControllerTest {
|
|||||||
usbLinkProperties.addRoute(
|
usbLinkProperties.addRoute(
|
||||||
new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST));
|
new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST));
|
||||||
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
offload.notifyDownstreamLinkProperties(usbLinkProperties);
|
||||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
|
inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DOC_PREFIX);
|
||||||
inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
|
inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DISCARD_PREFIX);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// [6] Removing a downstream interface which was never added causes no
|
// [6] Removing a downstream interface which was never added causes no
|
||||||
@@ -753,8 +752,8 @@ public class OffloadControllerTest {
|
|||||||
|
|
||||||
// [7] Removing an active downstream removes all remaining prefixes.
|
// [7] Removing an active downstream removes all remaining prefixes.
|
||||||
offload.removeDownstreamInterface(RNDIS0);
|
offload.removeDownstreamInterface(RNDIS0);
|
||||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, USB_PREFIX);
|
inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, USB_PREFIX);
|
||||||
inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
|
inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DISCARD_PREFIX);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +761,7 @@ public class OffloadControllerTest {
|
|||||||
public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception {
|
public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
// Pretend to set a few different upstreams (only the interface name
|
// Pretend to set a few different upstreams (only the interface name
|
||||||
// matters for this test; we're ignoring IP and route information).
|
// matters for this test; we're ignoring IP and route information).
|
||||||
@@ -776,7 +775,7 @@ public class OffloadControllerTest {
|
|||||||
// that happen with setUpstreamParameters().
|
// that happen with setUpstreamParameters().
|
||||||
clearInvocations(mHardware);
|
clearInvocations(mHardware);
|
||||||
|
|
||||||
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
|
OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue();
|
||||||
callback.onStoppedUnsupported();
|
callback.onStoppedUnsupported();
|
||||||
|
|
||||||
// Verify forwarded stats behaviour.
|
// Verify forwarded stats behaviour.
|
||||||
@@ -793,7 +792,7 @@ public class OffloadControllerTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
enableOffload();
|
enableOffload();
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
// Pretend to set a few different upstreams (only the interface name
|
// Pretend to set a few different upstreams (only the interface name
|
||||||
// matters for this test; we're ignoring IP and route information).
|
// matters for this test; we're ignoring IP and route information).
|
||||||
@@ -840,7 +839,7 @@ public class OffloadControllerTest {
|
|||||||
// that happen with setUpstreamParameters().
|
// that happen with setUpstreamParameters().
|
||||||
clearInvocations(mHardware);
|
clearInvocations(mHardware);
|
||||||
|
|
||||||
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
|
OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue();
|
||||||
callback.onSupportAvailable();
|
callback.onSupportAvailable();
|
||||||
|
|
||||||
// Verify forwarded stats behaviour.
|
// Verify forwarded stats behaviour.
|
||||||
@@ -859,8 +858,8 @@ public class OffloadControllerTest {
|
|||||||
// into OffloadController proper. After this, also check for:
|
// into OffloadController proper. After this, also check for:
|
||||||
// "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128"
|
// "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128"
|
||||||
"127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
|
"127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
|
||||||
verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24");
|
verify(mHardware, times(1)).addDownstream(WLAN0, "192.168.43.0/24");
|
||||||
verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64");
|
verify(mHardware, times(1)).addDownstream(WLAN0, "2001:2::/64");
|
||||||
verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any());
|
verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any());
|
||||||
verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong());
|
verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong());
|
||||||
verifyNoMoreInteractions(mHardware);
|
verifyNoMoreInteractions(mHardware);
|
||||||
@@ -871,7 +870,7 @@ public class OffloadControllerTest {
|
|||||||
enableOffload();
|
enableOffload();
|
||||||
setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
|
setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
|
||||||
final OffloadController offload =
|
final OffloadController offload =
|
||||||
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
|
startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/);
|
||||||
|
|
||||||
// Initialize with fake eth upstream.
|
// Initialize with fake eth upstream.
|
||||||
final String ethernetIface = "eth1";
|
final String ethernetIface = "eth1";
|
||||||
@@ -925,7 +924,7 @@ public class OffloadControllerTest {
|
|||||||
offload.setUpstreamLinkProperties(makeEthernetLinkProperties());
|
offload.setUpstreamLinkProperties(makeEthernetLinkProperties());
|
||||||
mTetherStatsProvider.onSetAlert(0);
|
mTetherStatsProvider.onSetAlert(0);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) {
|
||||||
mTetherStatsProviderCb.assertNoCallback();
|
mTetherStatsProviderCb.assertNoCallback();
|
||||||
} else {
|
} else {
|
||||||
mTetherStatsProviderCb.expectNotifyAlertReached();
|
mTetherStatsProviderCb.expectNotifyAlertReached();
|
||||||
@@ -935,7 +934,7 @@ public class OffloadControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSoftwarePollingUsed() throws Exception {
|
public void testSoftwarePollingUsed() throws Exception {
|
||||||
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_0);
|
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_1);
|
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.anyLong;
|
||||||
|
import static org.mockito.Mockito.anyString;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.hardware.tetheroffload.ForwardedStats;
|
||||||
|
import android.hardware.tetheroffload.IOffload;
|
||||||
|
import android.hardware.tetheroffload.IPv4AddrPortPair;
|
||||||
|
import android.hardware.tetheroffload.ITetheringOffloadCallback;
|
||||||
|
import android.hardware.tetheroffload.NatTimeoutUpdate;
|
||||||
|
import android.hardware.tetheroffload.NetworkProtocol;
|
||||||
|
import android.hardware.tetheroffload.OffloadCallbackEvent;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.ServiceSpecificException;
|
||||||
|
import android.os.test.TestLooper;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public final class OffloadHalAidlImplTest {
|
||||||
|
private static final String RMNET0 = "test_rmnet_data0";
|
||||||
|
|
||||||
|
private final SharedLog mLog = new SharedLog("test");
|
||||||
|
private final TestLooper mTestLooper = new TestLooper();
|
||||||
|
|
||||||
|
private IOffload mIOffloadMock;
|
||||||
|
private OffloadHalAidlImpl mIOffloadHal;
|
||||||
|
private ITetheringOffloadCallback mTetheringOffloadCallback;
|
||||||
|
private OffloadHalCallback mOffloadHalCallback;
|
||||||
|
|
||||||
|
private void initAndValidateOffloadHal(boolean initSuccess)
|
||||||
|
throws Exception {
|
||||||
|
final FileDescriptor fd1 = new FileDescriptor();
|
||||||
|
final FileDescriptor fd2 = new FileDescriptor();
|
||||||
|
final NativeHandle handle1 = new NativeHandle(fd1, true);
|
||||||
|
final NativeHandle handle2 = new NativeHandle(fd2, true);
|
||||||
|
final ArgumentCaptor<ParcelFileDescriptor> fdCaptor1 =
|
||||||
|
ArgumentCaptor.forClass(ParcelFileDescriptor.class);
|
||||||
|
final ArgumentCaptor<ParcelFileDescriptor> fdCaptor2 =
|
||||||
|
ArgumentCaptor.forClass(ParcelFileDescriptor.class);
|
||||||
|
final ArgumentCaptor<ITetheringOffloadCallback> offloadCallbackCaptor =
|
||||||
|
ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
|
||||||
|
if (initSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).initOffload(any(), any(), any());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalStateException()).when(mIOffloadMock).initOffload(any(), any(),
|
||||||
|
any());
|
||||||
|
}
|
||||||
|
assertEquals(mIOffloadHal.initOffload(handle1, handle2, mOffloadHalCallback),
|
||||||
|
initSuccess);
|
||||||
|
verify(mIOffloadMock).initOffload(fdCaptor1.capture(), fdCaptor2.capture(),
|
||||||
|
offloadCallbackCaptor.capture());
|
||||||
|
assertEquals(fdCaptor1.getValue().getFd(), fd1.getInt$());
|
||||||
|
assertEquals(fdCaptor2.getValue().getFd(), fd2.getInt$());
|
||||||
|
mTetheringOffloadCallback = offloadCallbackCaptor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mIOffloadMock = mock(IOffload.class);
|
||||||
|
mIOffloadHal = new OffloadHalAidlImpl(OFFLOAD_HAL_VERSION_AIDL, mIOffloadMock,
|
||||||
|
new Handler(mTestLooper.getLooper()), mLog);
|
||||||
|
mOffloadHalCallback = spy(new OffloadHalCallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitOffloadSuccess() throws Exception {
|
||||||
|
initAndValidateOffloadHal(true /* initSuccess */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitOffloadFailure() throws Exception {
|
||||||
|
initAndValidateOffloadHal(false /* initSuccess */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopOffloadSuccess() throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
doNothing().when(mIOffloadMock).stopOffload();
|
||||||
|
assertTrue(mIOffloadHal.stopOffload());
|
||||||
|
verify(mIOffloadMock).stopOffload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopOffloadFailure() throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
doThrow(new IllegalStateException()).when(mIOffloadMock).stopOffload();
|
||||||
|
assertFalse(mIOffloadHal.stopOffload());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestGetForwardedStats(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final ForwardedStats returnStats = new ForwardedStats();
|
||||||
|
if (expectSuccess) {
|
||||||
|
returnStats.rxBytes = 12345;
|
||||||
|
returnStats.txBytes = 67890;
|
||||||
|
when(mIOffloadMock.getForwardedStats(anyString())).thenReturn(returnStats);
|
||||||
|
} else {
|
||||||
|
when(mIOffloadMock.getForwardedStats(anyString()))
|
||||||
|
.thenThrow(new ServiceSpecificException(IOffload.ERROR_CODE_UNUSED));
|
||||||
|
}
|
||||||
|
final OffloadHardwareInterface.ForwardedStats stats =
|
||||||
|
mIOffloadHal.getForwardedStats(RMNET0);
|
||||||
|
verify(mIOffloadMock).getForwardedStats(eq(RMNET0));
|
||||||
|
assertNotNull(stats);
|
||||||
|
assertEquals(stats.rxBytes, returnStats.rxBytes);
|
||||||
|
assertEquals(stats.txBytes, returnStats.txBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetForwardedStatsSuccess() throws Exception {
|
||||||
|
doTestGetForwardedStats(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetForwardedStatsFailure() throws Exception {
|
||||||
|
doTestGetForwardedStats(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetLocalPrefixes(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final ArrayList<String> localPrefixes = new ArrayList<>();
|
||||||
|
localPrefixes.add("127.0.0.0/8");
|
||||||
|
localPrefixes.add("fe80::/64");
|
||||||
|
final String[] localPrefixesArray =
|
||||||
|
localPrefixes.toArray(new String[localPrefixes.size()]);
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).setLocalPrefixes(any());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalArgumentException()).when(mIOffloadMock).setLocalPrefixes(any());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setLocalPrefixes(localPrefixes));
|
||||||
|
verify(mIOffloadMock).setLocalPrefixes(eq(localPrefixesArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLocalPrefixesSuccess() throws Exception {
|
||||||
|
doTestSetLocalPrefixes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLocalPrefixesFailure() throws Exception {
|
||||||
|
doTestSetLocalPrefixes(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetDataLimit(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final long limit = 12345;
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(),
|
||||||
|
anyLong());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalArgumentException())
|
||||||
|
.when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), anyLong());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setDataLimit(RMNET0, limit));
|
||||||
|
verify(mIOffloadMock).setDataWarningAndLimit(eq(RMNET0), eq(Long.MAX_VALUE), eq(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataLimitSuccess() throws Exception {
|
||||||
|
doTestSetDataLimit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataLimitFailure() throws Exception {
|
||||||
|
doTestSetDataLimit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetDataWarningAndLimit(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final long warning = 12345;
|
||||||
|
final long limit = 67890;
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(),
|
||||||
|
anyLong());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalArgumentException())
|
||||||
|
.when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), anyLong());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
|
verify(mIOffloadMock).setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimitSuccess() throws Exception {
|
||||||
|
doTestSetDataWarningAndLimit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimitFailure() throws Exception {
|
||||||
|
doTestSetDataWarningAndLimit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetUpstreamParameters(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final String v4addr = "192.168.10.1";
|
||||||
|
final String v4gateway = "192.168.10.255";
|
||||||
|
final ArrayList<String> v6gws = new ArrayList<>(0);
|
||||||
|
v6gws.add("2001:db8::1");
|
||||||
|
String[] v6gwsArray = v6gws.toArray(new String[v6gws.size()]);
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).setUpstreamParameters(anyString(), anyString(),
|
||||||
|
anyString(), any());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalArgumentException()).when(mIOffloadMock).setUpstreamParameters(
|
||||||
|
anyString(), anyString(), anyString(), any());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setUpstreamParameters(RMNET0, v4addr, v4gateway,
|
||||||
|
v6gws));
|
||||||
|
verify(mIOffloadMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
|
||||||
|
eq(v6gwsArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUpstreamParametersSuccess() throws Exception {
|
||||||
|
doTestSetUpstreamParameters(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUpstreamParametersFailure() throws Exception {
|
||||||
|
doTestSetUpstreamParameters(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestAddDownstream(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final String ifName = "wlan1";
|
||||||
|
final String prefix = "192.168.43.0/24";
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).addDownstream(anyString(), anyString());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalStateException()).when(mIOffloadMock).addDownstream(anyString(),
|
||||||
|
anyString());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.addDownstream(ifName, prefix));
|
||||||
|
verify(mIOffloadMock).addDownstream(eq(ifName), eq(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDownstreamSuccess() throws Exception {
|
||||||
|
doTestAddDownstream(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDownstreamFailure() throws Exception {
|
||||||
|
doTestAddDownstream(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestRemoveDownstream(boolean expectSuccess) throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
final String ifName = "wlan1";
|
||||||
|
final String prefix = "192.168.43.0/24";
|
||||||
|
if (expectSuccess) {
|
||||||
|
doNothing().when(mIOffloadMock).removeDownstream(anyString(), anyString());
|
||||||
|
} else {
|
||||||
|
doThrow(new IllegalArgumentException()).when(mIOffloadMock).removeDownstream(
|
||||||
|
anyString(), anyString());
|
||||||
|
}
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.removeDownstream(ifName, prefix));
|
||||||
|
verify(mIOffloadMock).removeDownstream(eq(ifName), eq(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveDownstreamSuccess() throws Exception {
|
||||||
|
doTestRemoveDownstream(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveDownstreamFailure() throws Exception {
|
||||||
|
doTestRemoveDownstream(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTetheringOffloadCallback() throws Exception {
|
||||||
|
initAndValidateOffloadHal(true);
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
final InOrder inOrder = inOrder(mOffloadHalCallback);
|
||||||
|
inOrder.verify(mOffloadHalCallback).onStarted();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onStoppedError();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onStoppedUnsupported();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onSupportAvailable();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onStoppedLimitReached();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onWarningReached();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
|
||||||
|
mTetheringOffloadCallback.updateTimeout(tcpParams);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
|
||||||
|
eq(tcpParams.src.addr),
|
||||||
|
eq(tcpParams.src.port),
|
||||||
|
eq(tcpParams.dst.addr),
|
||||||
|
eq(tcpParams.dst.port));
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
|
||||||
|
mTetheringOffloadCallback.updateTimeout(udpParams);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
|
||||||
|
eq(udpParams.src.addr),
|
||||||
|
eq(udpParams.src.port),
|
||||||
|
eq(udpParams.dst.addr),
|
||||||
|
eq(udpParams.dst.port));
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
|
||||||
|
final NatTimeoutUpdate params = new NatTimeoutUpdate();
|
||||||
|
params.proto = proto;
|
||||||
|
params.src = new IPv4AddrPortPair();
|
||||||
|
params.dst = new IPv4AddrPortPair();
|
||||||
|
params.src.addr = "192.168.43.200";
|
||||||
|
params.src.port = 100;
|
||||||
|
params.dst.addr = "172.50.46.169";
|
||||||
|
params.dst.port = 150;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
|
import static com.android.networkstack.tethering.util.TetheringUtils.uint16;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
||||||
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
|
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
||||||
|
import android.hardware.tetheroffload.control.V1_1.OffloadCallbackEvent;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.NativeHandle;
|
||||||
|
import android.os.test.TestLooper;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public final class OffloadHalHidlImplTest {
|
||||||
|
private static final String RMNET0 = "test_rmnet_data0";
|
||||||
|
|
||||||
|
private final SharedLog mLog = new SharedLog("test");
|
||||||
|
private final TestLooper mTestLooper = new TestLooper();
|
||||||
|
|
||||||
|
private OffloadHalHidlImpl mIOffloadHal;
|
||||||
|
private IOffloadConfig mIOffloadConfigMock;
|
||||||
|
private IOffloadControl mIOffloadControlMock;
|
||||||
|
private ITetheringOffloadCallback mTetheringOffloadCallback;
|
||||||
|
private OffloadHalCallback mOffloadHalCallback;
|
||||||
|
|
||||||
|
private void createAndInitOffloadHal(int version) throws Exception {
|
||||||
|
final FileDescriptor fd1 = new FileDescriptor();
|
||||||
|
final FileDescriptor fd2 = new FileDescriptor();
|
||||||
|
final NativeHandle handle1 = new NativeHandle(fd1, true);
|
||||||
|
final NativeHandle handle2 = new NativeHandle(fd2, true);
|
||||||
|
mIOffloadConfigMock = mock(IOffloadConfig.class);
|
||||||
|
switch (version) {
|
||||||
|
case OFFLOAD_HAL_VERSION_HIDL_1_0:
|
||||||
|
mIOffloadControlMock = mock(IOffloadControl.class);
|
||||||
|
break;
|
||||||
|
case OFFLOAD_HAL_VERSION_HIDL_1_1:
|
||||||
|
mIOffloadControlMock = mock(
|
||||||
|
android.hardware.tetheroffload.control.V1_1.IOffloadControl.class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Nonexistent HAL version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIOffloadHal = new OffloadHalHidlImpl(version, mIOffloadConfigMock,
|
||||||
|
mIOffloadControlMock, new Handler(mTestLooper.getLooper()), mLog);
|
||||||
|
mIOffloadHal.initOffload(handle1, handle2, mOffloadHalCallback);
|
||||||
|
|
||||||
|
final ArgumentCaptor<NativeHandle> nativeHandleCaptor1 =
|
||||||
|
ArgumentCaptor.forClass(NativeHandle.class);
|
||||||
|
final ArgumentCaptor<NativeHandle> nativeHandleCaptor2 =
|
||||||
|
ArgumentCaptor.forClass(NativeHandle.class);
|
||||||
|
final ArgumentCaptor<ITetheringOffloadCallback> offloadCallbackCaptor =
|
||||||
|
ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
|
||||||
|
verify(mIOffloadConfigMock).setHandles(nativeHandleCaptor1.capture(),
|
||||||
|
nativeHandleCaptor2.capture(), any());
|
||||||
|
verify(mIOffloadControlMock).initOffload(offloadCallbackCaptor.capture(), any());
|
||||||
|
assertEquals(nativeHandleCaptor1.getValue().getFileDescriptor().getInt$(),
|
||||||
|
handle1.getFileDescriptor().getInt$());
|
||||||
|
assertEquals(nativeHandleCaptor2.getValue().getFileDescriptor().getInt$(),
|
||||||
|
handle2.getFileDescriptor().getInt$());
|
||||||
|
mTetheringOffloadCallback = offloadCallbackCaptor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mOffloadHalCallback = spy(new OffloadHalCallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetForwardedStats() throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final long rxBytes = 12345;
|
||||||
|
final long txBytes = 67890;
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.getForwardedStatsCallback) invocation.getArgument(1))
|
||||||
|
.onValues(rxBytes, txBytes);
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).getForwardedStats(eq(RMNET0), any());
|
||||||
|
final ForwardedStats stats = mIOffloadHal.getForwardedStats(RMNET0);
|
||||||
|
verify(mIOffloadControlMock).getForwardedStats(eq(RMNET0), any());
|
||||||
|
assertNotNull(stats);
|
||||||
|
assertEquals(rxBytes, stats.rxBytes);
|
||||||
|
assertEquals(txBytes, stats.txBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetLocalPrefixes(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final ArrayList<String> localPrefixes = new ArrayList<>();
|
||||||
|
localPrefixes.add("127.0.0.0/8");
|
||||||
|
localPrefixes.add("fe80::/64");
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.setLocalPrefixesCallback) invocation.getArgument(1))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).setLocalPrefixes(eq(localPrefixes), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setLocalPrefixes(localPrefixes));
|
||||||
|
verify(mIOffloadControlMock).setLocalPrefixes(eq(localPrefixes), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLocalPrefixesSuccess() throws Exception {
|
||||||
|
doTestSetLocalPrefixes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLocalPrefixesFailure() throws Exception {
|
||||||
|
doTestSetLocalPrefixes(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetDataLimit(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final long limit = 12345;
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.setDataLimitCallback) invocation.getArgument(2))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).setDataLimit(eq(RMNET0), eq(limit), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setDataLimit(RMNET0, limit));
|
||||||
|
verify(mIOffloadControlMock).setDataLimit(eq(RMNET0), eq(limit), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataLimitSuccess() throws Exception {
|
||||||
|
doTestSetDataLimit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataLimitFailure() throws Exception {
|
||||||
|
doTestSetDataLimit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetDataWarningAndLimit(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
|
final long warning = 12345;
|
||||||
|
final long limit = 67890;
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((android.hardware.tetheroffload.control.V1_1.IOffloadControl
|
||||||
|
.setDataWarningAndLimitCallback) invocation.getArgument(3))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControlMock)
|
||||||
|
.setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
|
verify((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControlMock)
|
||||||
|
.setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimitSuccess() throws Exception {
|
||||||
|
doTestSetDataWarningAndLimit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimitFailure() throws Exception {
|
||||||
|
// Verify that V1.0 control HAL would reject the function call with exception.
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final long warning = 12345;
|
||||||
|
final long limit = 67890;
|
||||||
|
assertThrows(UnsupportedOperationException.class,
|
||||||
|
() -> mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
|
|
||||||
|
doTestSetDataWarningAndLimit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestSetUpstreamParameters(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final String v4addr = "192.168.10.1";
|
||||||
|
final String v4gateway = "192.168.10.255";
|
||||||
|
final ArrayList<String> v6gws = new ArrayList<>(0);
|
||||||
|
v6gws.add("2001:db8::1");
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.setUpstreamParametersCallback) invocation.getArgument(4))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
|
||||||
|
eq(v6gws), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.setUpstreamParameters(RMNET0, v4addr, v4gateway,
|
||||||
|
v6gws));
|
||||||
|
verify(mIOffloadControlMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
|
||||||
|
eq(v6gws), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUpstreamParametersSuccess() throws Exception {
|
||||||
|
doTestSetUpstreamParameters(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUpstreamParametersFailure() throws Exception {
|
||||||
|
doTestSetUpstreamParameters(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestAddDownstream(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final String ifName = "wlan1";
|
||||||
|
final String prefix = "192.168.43.0/24";
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.addDownstreamCallback) invocation.getArgument(2))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).addDownstream(eq(ifName), eq(prefix), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.addDownstream(ifName, prefix));
|
||||||
|
verify(mIOffloadControlMock).addDownstream(eq(ifName), eq(prefix), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDownstreamSuccess() throws Exception {
|
||||||
|
doTestAddDownstream(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDownstreamFailure() throws Exception {
|
||||||
|
doTestAddDownstream(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestRemoveDownstream(boolean expectSuccess) throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final String ifName = "wlan1";
|
||||||
|
final String prefix = "192.168.43.0/24";
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
((IOffloadControl.removeDownstreamCallback) invocation.getArgument(2))
|
||||||
|
.onValues(expectSuccess, "");
|
||||||
|
return null;
|
||||||
|
}).when(mIOffloadControlMock).removeDownstream(eq(ifName), eq(prefix), any());
|
||||||
|
assertEquals(expectSuccess, mIOffloadHal.removeDownstream(ifName, prefix));
|
||||||
|
verify(mIOffloadControlMock).removeDownstream(eq(ifName), eq(prefix), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveDownstreamSuccess() throws Exception {
|
||||||
|
doTestRemoveDownstream(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveDownstreamFailure() throws Exception {
|
||||||
|
doTestRemoveDownstream(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTetheringOffloadCallback() throws Exception {
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onStarted();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onStoppedError();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onStoppedUnsupported();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onSupportAvailable();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onStoppedLimitReached();
|
||||||
|
|
||||||
|
final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
|
||||||
|
mTetheringOffloadCallback.updateTimeout(tcpParams);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
|
||||||
|
eq(tcpParams.src.addr),
|
||||||
|
eq(uint16(tcpParams.src.port)),
|
||||||
|
eq(tcpParams.dst.addr),
|
||||||
|
eq(uint16(tcpParams.dst.port)));
|
||||||
|
|
||||||
|
final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
|
||||||
|
mTetheringOffloadCallback.updateTimeout(udpParams);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
|
||||||
|
eq(udpParams.src.addr),
|
||||||
|
eq(uint16(udpParams.src.port)),
|
||||||
|
eq(udpParams.dst.addr),
|
||||||
|
eq(uint16(udpParams.dst.port)));
|
||||||
|
reset(mOffloadHalCallback);
|
||||||
|
|
||||||
|
createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
|
|
||||||
|
// Verify the interface will process the events that comes from V1.1 HAL.
|
||||||
|
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_STARTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
final InOrder inOrder = inOrder(mOffloadHalCallback);
|
||||||
|
inOrder.verify(mOffloadHalCallback).onStarted();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mOffloadHalCallback).onWarningReached();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
|
||||||
|
final NatTimeoutUpdate params = new NatTimeoutUpdate();
|
||||||
|
params.proto = proto;
|
||||||
|
params.src.addr = "192.168.43.200";
|
||||||
|
params.src.port = 100;
|
||||||
|
params.dst.addr = "172.50.46.169";
|
||||||
|
params.dst.port = 150;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,36 +20,29 @@ import static android.system.OsConstants.AF_INET;
|
|||||||
import static android.system.OsConstants.AF_UNIX;
|
import static android.system.OsConstants.AF_UNIX;
|
||||||
import static android.system.OsConstants.SOCK_STREAM;
|
import static android.system.OsConstants.SOCK_STREAM;
|
||||||
|
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
|
||||||
import static com.android.networkstack.tethering.util.TetheringUtils.uint16;
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
|
||||||
|
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.reset;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
|
||||||
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
|
||||||
import android.hardware.tetheroffload.control.V1_1.OffloadCallbackEvent;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.NativeHandle;
|
import android.os.NativeHandle;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
@@ -57,12 +50,13 @@ import androidx.test.runner.AndroidJUnit4;
|
|||||||
import com.android.net.module.util.SharedLog;
|
import com.android.net.module.util.SharedLog;
|
||||||
import com.android.net.module.util.netlink.StructNfGenMsg;
|
import com.android.net.module.util.netlink.StructNfGenMsg;
|
||||||
import com.android.net.module.util.netlink.StructNlMsgHdr;
|
import com.android.net.module.util.netlink.StructNlMsgHdr;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
|
||||||
|
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
|
||||||
|
|
||||||
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.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -79,11 +73,9 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
private final TestLooper mTestLooper = new TestLooper();
|
private final TestLooper mTestLooper = new TestLooper();
|
||||||
|
|
||||||
private OffloadHardwareInterface mOffloadHw;
|
private OffloadHardwareInterface mOffloadHw;
|
||||||
private ITetheringOffloadCallback mTetheringOffloadCallback;
|
private OffloadHalCallback mOffloadHalCallback;
|
||||||
private OffloadHardwareInterface.ControlCallback mControlCallback;
|
|
||||||
|
|
||||||
@Mock private IOffloadConfig mIOffloadConfig;
|
@Mock private IOffloadHal mIOffload;
|
||||||
private IOffloadControl mIOffloadControl;
|
|
||||||
@Mock private NativeHandle mNativeHandle;
|
@Mock private NativeHandle mNativeHandle;
|
||||||
|
|
||||||
// Random values to test Netlink message.
|
// Random values to test Netlink message.
|
||||||
@@ -91,32 +83,16 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
private static final short TEST_FLAGS = 263;
|
private static final short TEST_FLAGS = 263;
|
||||||
|
|
||||||
class MyDependencies extends OffloadHardwareInterface.Dependencies {
|
class MyDependencies extends OffloadHardwareInterface.Dependencies {
|
||||||
private final int mMockControlVersion;
|
private final int mMockOffloadHalVersion;
|
||||||
MyDependencies(SharedLog log, final int mockControlVersion) {
|
MyDependencies(Handler handler, SharedLog log, final int mockOffloadHalVersion) {
|
||||||
super(log);
|
super(handler, log);
|
||||||
mMockControlVersion = mockControlVersion;
|
mMockOffloadHalVersion = mockOffloadHalVersion;
|
||||||
|
when(mIOffload.getVersion()).thenReturn(mMockOffloadHalVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IOffloadConfig getOffloadConfig() {
|
public IOffloadHal getOffload() {
|
||||||
return mIOffloadConfig;
|
return mMockOffloadHalVersion == OFFLOAD_HAL_VERSION_NONE ? null : mIOffload;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Pair<IOffloadControl, Integer> getOffloadControl() {
|
|
||||||
switch (mMockControlVersion) {
|
|
||||||
case OFFLOAD_HAL_VERSION_1_0:
|
|
||||||
mIOffloadControl = mock(IOffloadControl.class);
|
|
||||||
break;
|
|
||||||
case OFFLOAD_HAL_VERSION_1_1:
|
|
||||||
mIOffloadControl =
|
|
||||||
mock(android.hardware.tetheroffload.control.V1_1.IOffloadControl.class);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid offload control version "
|
|
||||||
+ mMockControlVersion);
|
|
||||||
}
|
|
||||||
return new Pair<IOffloadControl, Integer>(mIOffloadControl, mMockControlVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -128,156 +104,140 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
|
mOffloadHalCallback = new OffloadHalCallback();
|
||||||
|
when(mIOffload.initOffload(any(NativeHandle.class), any(NativeHandle.class),
|
||||||
|
any(OffloadHalCallback.class))).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startOffloadHardwareInterface(int controlVersion) throws Exception {
|
private void startOffloadHardwareInterface(int offloadHalVersion)
|
||||||
|
throws Exception {
|
||||||
final SharedLog log = new SharedLog("test");
|
final SharedLog log = new SharedLog("test");
|
||||||
mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
|
final Handler handler = new Handler(mTestLooper.getLooper());
|
||||||
new MyDependencies(log, controlVersion));
|
final int num = offloadHalVersion != OFFLOAD_HAL_VERSION_NONE ? 1 : 0;
|
||||||
mOffloadHw.initOffloadConfig();
|
mOffloadHw = new OffloadHardwareInterface(handler, log,
|
||||||
mOffloadHw.initOffloadControl(mControlCallback);
|
new MyDependencies(handler, log, offloadHalVersion));
|
||||||
final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
|
assertEquals(offloadHalVersion, mOffloadHw.initOffload(mOffloadHalCallback));
|
||||||
ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
|
verify(mIOffload, times(num)).initOffload(any(NativeHandle.class), any(NativeHandle.class),
|
||||||
verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any());
|
eq(mOffloadHalCallback));
|
||||||
mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue();
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureWithNoHal() throws Exception {
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitSuccessWithAidl() throws Exception {
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitSuccessWithHidl_1_0() throws Exception {
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitSuccessWithHidl_1_1() throws Exception {
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetForwardedStats() throws Exception {
|
public void testGetForwardedStats() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
|
ForwardedStats stats = new ForwardedStats(12345, 56780);
|
||||||
verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
|
when(mIOffload.getForwardedStats(anyString())).thenReturn(stats);
|
||||||
assertNotNull(stats);
|
assertEquals(mOffloadHw.getForwardedStats(RMNET0), stats);
|
||||||
|
verify(mIOffload).getForwardedStats(eq(RMNET0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetLocalPrefixes() throws Exception {
|
public void testSetLocalPrefixes() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
final ArrayList<String> localPrefixes = new ArrayList<>();
|
final ArrayList<String> localPrefixes = new ArrayList<>();
|
||||||
localPrefixes.add("127.0.0.0/8");
|
localPrefixes.add("127.0.0.0/8");
|
||||||
localPrefixes.add("fe80::/64");
|
localPrefixes.add("fe80::/64");
|
||||||
mOffloadHw.setLocalPrefixes(localPrefixes);
|
when(mIOffload.setLocalPrefixes(any())).thenReturn(true);
|
||||||
verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any());
|
assertTrue(mOffloadHw.setLocalPrefixes(localPrefixes));
|
||||||
|
verify(mIOffload).setLocalPrefixes(eq(localPrefixes));
|
||||||
|
when(mIOffload.setLocalPrefixes(any())).thenReturn(false);
|
||||||
|
assertFalse(mOffloadHw.setLocalPrefixes(localPrefixes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetDataLimit() throws Exception {
|
public void testSetDataLimit() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
final long limit = 12345;
|
final long limit = 12345;
|
||||||
mOffloadHw.setDataLimit(RMNET0, limit);
|
when(mIOffload.setDataLimit(anyString(), anyLong())).thenReturn(true);
|
||||||
verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
|
assertTrue(mOffloadHw.setDataLimit(RMNET0, limit));
|
||||||
|
verify(mIOffload).setDataLimit(eq(RMNET0), eq(limit));
|
||||||
|
when(mIOffload.setDataLimit(anyString(), anyLong())).thenReturn(false);
|
||||||
|
assertFalse(mOffloadHw.setDataLimit(RMNET0, limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimitFailureWithHidl_1_0() throws Exception {
|
||||||
|
// Verify V1.0 control HAL would reject the function call with exception.
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
|
final long warning = 12345;
|
||||||
|
final long limit = 67890;
|
||||||
|
assertThrows(UnsupportedOperationException.class,
|
||||||
|
() -> mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetDataWarningAndLimit() throws Exception {
|
public void testSetDataWarningAndLimit() throws Exception {
|
||||||
// Verify V1.0 control HAL would reject the function call with exception.
|
// Verify V1.1 control HAL could receive this function call.
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1);
|
||||||
final long warning = 12345;
|
final long warning = 12345;
|
||||||
final long limit = 67890;
|
final long limit = 67890;
|
||||||
assertThrows(IllegalArgumentException.class,
|
when(mIOffload.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
|
||||||
() -> mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit));
|
assertTrue(mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
reset(mIOffloadControl);
|
verify(mIOffload).setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit));
|
||||||
|
when(mIOffload.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(false);
|
||||||
// Verify V1.1 control HAL could receive this function call.
|
assertFalse(mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1);
|
|
||||||
mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit);
|
|
||||||
verify((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControl)
|
|
||||||
.setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetUpstreamParameters() throws Exception {
|
public void testSetUpstreamParameters() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
final String v4addr = "192.168.10.1";
|
final String v4addr = "192.168.10.1";
|
||||||
final String v4gateway = "192.168.10.255";
|
final String v4gateway = "192.168.10.255";
|
||||||
final ArrayList<String> v6gws = new ArrayList<>(0);
|
final ArrayList<String> v6gws = new ArrayList<>(0);
|
||||||
v6gws.add("2001:db8::1");
|
v6gws.add("2001:db8::1");
|
||||||
mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws);
|
when(mIOffload.setUpstreamParameters(anyString(), anyString(), anyString(), any()))
|
||||||
verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
|
.thenReturn(true);
|
||||||
eq(v6gws), any());
|
assertTrue(mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws));
|
||||||
|
verify(mIOffload).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), eq(v6gws));
|
||||||
|
|
||||||
final ArgumentCaptor<ArrayList<String>> mArrayListCaptor =
|
final ArgumentCaptor<ArrayList<String>> mArrayListCaptor =
|
||||||
ArgumentCaptor.forClass(ArrayList.class);
|
ArgumentCaptor.forClass(ArrayList.class);
|
||||||
mOffloadHw.setUpstreamParameters(null, null, null, null);
|
when(mIOffload.setUpstreamParameters(anyString(), anyString(), anyString(), any()))
|
||||||
verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""),
|
.thenReturn(false);
|
||||||
mArrayListCaptor.capture(), any());
|
assertFalse(mOffloadHw.setUpstreamParameters(null, null, null, null));
|
||||||
|
verify(mIOffload).setUpstreamParameters(eq(""), eq(""), eq(""), mArrayListCaptor.capture());
|
||||||
assertEquals(mArrayListCaptor.getValue().size(), 0);
|
assertEquals(mArrayListCaptor.getValue().size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateDownstreamPrefix() throws Exception {
|
public void testUpdateDownstream() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
final String ifName = "wlan1";
|
final String ifName = "wlan1";
|
||||||
final String prefix = "192.168.43.0/24";
|
final String prefix = "192.168.43.0/24";
|
||||||
mOffloadHw.addDownstreamPrefix(ifName, prefix);
|
when(mIOffload.addDownstream(anyString(), anyString())).thenReturn(true);
|
||||||
verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any());
|
assertTrue(mOffloadHw.addDownstream(ifName, prefix));
|
||||||
|
verify(mIOffload).addDownstream(eq(ifName), eq(prefix));
|
||||||
mOffloadHw.removeDownstreamPrefix(ifName, prefix);
|
when(mIOffload.addDownstream(anyString(), anyString())).thenReturn(false);
|
||||||
verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any());
|
assertFalse(mOffloadHw.addDownstream(ifName, prefix));
|
||||||
}
|
when(mIOffload.removeDownstream(anyString(), anyString())).thenReturn(true);
|
||||||
|
assertTrue(mOffloadHw.removeDownstream(ifName, prefix));
|
||||||
@Test
|
verify(mIOffload).removeDownstream(eq(ifName), eq(prefix));
|
||||||
public void testTetheringOffloadCallback() throws Exception {
|
when(mIOffload.removeDownstream(anyString(), anyString())).thenReturn(false);
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
assertFalse(mOffloadHw.removeDownstream(ifName, prefix));
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onStarted();
|
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onStoppedError();
|
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onStoppedUnsupported();
|
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onSupportAvailable();
|
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onStoppedLimitReached();
|
|
||||||
|
|
||||||
final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
|
|
||||||
mTetheringOffloadCallback.updateTimeout(tcpParams);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
|
|
||||||
eq(tcpParams.src.addr),
|
|
||||||
eq(uint16(tcpParams.src.port)),
|
|
||||||
eq(tcpParams.dst.addr),
|
|
||||||
eq(uint16(tcpParams.dst.port)));
|
|
||||||
|
|
||||||
final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
|
|
||||||
mTetheringOffloadCallback.updateTimeout(udpParams);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
|
|
||||||
eq(udpParams.src.addr),
|
|
||||||
eq(uint16(udpParams.src.port)),
|
|
||||||
eq(udpParams.dst.addr),
|
|
||||||
eq(uint16(udpParams.dst.port)));
|
|
||||||
reset(mControlCallback);
|
|
||||||
|
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1);
|
|
||||||
|
|
||||||
// Verify the interface will process the events that comes from V1.1 HAL.
|
|
||||||
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_STARTED);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
final InOrder inOrder = inOrder(mControlCallback);
|
|
||||||
inOrder.verify(mControlCallback).onStarted();
|
|
||||||
inOrder.verifyNoMoreInteractions();
|
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED);
|
|
||||||
mTestLooper.dispatchAll();
|
|
||||||
inOrder.verify(mControlCallback).onWarningReached();
|
|
||||||
inOrder.verifyNoMoreInteractions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendIpv4NfGenMsg() throws Exception {
|
public void testSendIpv4NfGenMsg() throws Exception {
|
||||||
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
|
||||||
FileDescriptor writeSocket = new FileDescriptor();
|
FileDescriptor writeSocket = new FileDescriptor();
|
||||||
FileDescriptor readSocket = new FileDescriptor();
|
FileDescriptor readSocket = new FileDescriptor();
|
||||||
try {
|
try {
|
||||||
@@ -308,14 +268,4 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
assertEquals(0 /* error */, buffer.getShort()); // res_id
|
assertEquals(0 /* error */, buffer.getShort()); // res_id
|
||||||
assertEquals(expectedLen, buffer.position());
|
assertEquals(expectedLen, buffer.position());
|
||||||
}
|
}
|
||||||
|
|
||||||
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
|
|
||||||
final NatTimeoutUpdate params = new NatTimeoutUpdate();
|
|
||||||
params.proto = proto;
|
|
||||||
params.src.addr = "192.168.43.200";
|
|
||||||
params.src.port = 100;
|
|
||||||
params.dst.addr = "172.50.46.169";
|
|
||||||
params.dst.port = 150;
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
|
|||||||
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
|
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
|
||||||
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
|
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
|
||||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
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_HIDL_1_0;
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
|
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.BROADCAST_FIRST;
|
||||||
import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST;
|
import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST;
|
||||||
@@ -649,8 +649,7 @@ public class TetheringTest {
|
|||||||
mInterfaceConfiguration.flags = new String[0];
|
mInterfaceConfiguration.flags = new String[0];
|
||||||
when(mRouterAdvertisementDaemon.start())
|
when(mRouterAdvertisementDaemon.start())
|
||||||
.thenReturn(true);
|
.thenReturn(true);
|
||||||
initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0,
|
initOffloadConfiguration(OFFLOAD_HAL_VERSION_HIDL_1_0, 0 /* defaultDisabled */);
|
||||||
0 /* defaultDisabled */);
|
|
||||||
when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats);
|
when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats);
|
||||||
|
|
||||||
mServiceContext = new TestContext(mContext);
|
mServiceContext = new TestContext(mContext);
|
||||||
@@ -2345,25 +2344,15 @@ public class TetheringTest {
|
|||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||||
|
|
||||||
// 1. Offload fail if no OffloadConfig.
|
// 1. Offload fail if no IOffloadHal.
|
||||||
initOffloadConfiguration(false /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0,
|
initOffloadConfiguration(OFFLOAD_HAL_VERSION_NONE, 0 /* defaultDisabled */);
|
||||||
0 /* defaultDisabled */);
|
|
||||||
runUsbTethering(upstreamState);
|
runUsbTethering(upstreamState);
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
||||||
runStopUSBTethering();
|
runStopUSBTethering();
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||||
reset(mUsbManager, mIPv6TetheringCoordinator);
|
reset(mUsbManager, mIPv6TetheringCoordinator);
|
||||||
// 2. Offload fail if no OffloadControl.
|
// 2. Offload fail if disabled by settings.
|
||||||
initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_NONE,
|
initOffloadConfiguration(OFFLOAD_HAL_VERSION_HIDL_1_0, 1 /* defaultDisabled */);
|
||||||
0 /* defaultDisabled */);
|
|
||||||
runUsbTethering(upstreamState);
|
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
|
||||||
runStopUSBTethering();
|
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
|
||||||
reset(mUsbManager, mIPv6TetheringCoordinator);
|
|
||||||
// 3. Offload fail if disabled by settings.
|
|
||||||
initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0,
|
|
||||||
1 /* defaultDisabled */);
|
|
||||||
runUsbTethering(upstreamState);
|
runUsbTethering(upstreamState);
|
||||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
||||||
runStopUSBTethering();
|
runStopUSBTethering();
|
||||||
@@ -2378,11 +2367,10 @@ public class TetheringTest {
|
|||||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initOffloadConfiguration(final boolean offloadConfig,
|
private void initOffloadConfiguration(
|
||||||
@OffloadHardwareInterface.OffloadHalVersion final int offloadControlVersion,
|
@OffloadHardwareInterface.OffloadHalVersion final int offloadHalVersion,
|
||||||
final int defaultDisabled) {
|
final int defaultDisabled) {
|
||||||
when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig);
|
when(mOffloadHardwareInterface.initOffload(any())).thenReturn(offloadHalVersion);
|
||||||
when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControlVersion);
|
|
||||||
when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn(
|
when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn(
|
||||||
defaultDisabled);
|
defaultDisabled);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user