Merge "Add tethering offload HAL call via JNI"

This commit is contained in:
Treehugger Robot
2017-05-17 07:09:13 +00:00
committed by Gerrit Code Review
10 changed files with 325 additions and 14 deletions

View File

@@ -18,10 +18,18 @@ LOCAL_SRC_FILES += \
LOCAL_AIDL_INCLUDES += \
system/netd/server/binder
LOCAL_JAVA_LIBRARIES := services.net
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_shared2 tzdata_update2
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_JAVA_LIBRARIES := \
services.net \
android.hidl.manager-V1.0-java \
LOCAL_STATIC_JAVA_LIBRARIES := \
tzdata_shared2 \
tzdata_update2 \
android.hidl.base-V1.0-java-static \
android.hardware.tetheroffload.control-V1.0-java-static \
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental

View File

@@ -145,6 +145,7 @@ import com.android.server.connectivity.NetworkNotificationManager.NotificationTy
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -802,8 +803,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTestMode = mSystemProperties.get("cm.test.mode").equals("true")
&& mSystemProperties.get("ro.build.type").equals("eng");
mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties());
mTethering = makeTethering();
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -853,6 +853,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
mMultinetworkPolicyTracker.start();
}
private Tethering makeTethering() {
// TODO: Move other elements into @Overridden getters.
final TetheringDependencies deps = new TetheringDependencies();
return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
}
private NetworkRequest createInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities();

View File

@@ -81,6 +81,7 @@ import com.android.server.connectivity.tethering.OffloadController;
import com.android.server.connectivity.tethering.SimChangeListener;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
import com.android.server.net.BaseNetworkObserver;
@@ -178,7 +179,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
public Tethering(Context context, INetworkManagementService nmService,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
Looper looper, MockableSystemProperties systemProperties) {
Looper looper, MockableSystemProperties systemProperties,
TetheringDependencies deps) {
mLocalLog.log("CONSTRUCTED");
mContext = context;
mNMService = nmService;
@@ -194,7 +196,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
mOffloadController = new OffloadController(mTetherMasterSM.getHandler());
mOffloadController = new OffloadController(mTetherMasterSM.getHandler(),
deps.getOffloadHardwareInterface());
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
@@ -1474,7 +1477,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
handleInterfaceServingStateInactive(who);
if (mNotifyList.isEmpty()) {
// transitions appropriately
// This transitions us out of TetherModeAliveState,
// either to InitialState or an error state.
turnOffMasterTetherSettings();
break;
}

View File

@@ -18,10 +18,12 @@ package com.android.server.connectivity.tethering;
import android.net.LinkProperties;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
/**
* A wrapper around hardware offload interface.
* A class to encapsulate the business logic of programming the tethering
* hardware offload interface.
*
* @hide
*/
@@ -29,25 +31,48 @@ public class OffloadController {
private static final String TAG = OffloadController.class.getSimpleName();
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private boolean mConfigInitialized;
private boolean mControlInitialized;
private LinkProperties mUpstreamLinkProperties;
public OffloadController(Handler h) {
public OffloadController(Handler h, OffloadHardwareInterface hwi) {
mHandler = h;
mHwInterface = hwi;
}
public void start() {
// TODO: initOffload() and configure callbacks to be handled on our
// preferred Handler.
Log.d(TAG, "tethering offload not supported");
if (started()) return;
if (!mConfigInitialized) {
mConfigInitialized = mHwInterface.initOffloadConfig();
if (!mConfigInitialized) {
Log.d(TAG, "tethering offload config not supported");
return;
}
}
// TODO: Create and register ITetheringOffloadCallback.
mControlInitialized = mHwInterface.initOffloadControl();
}
public void stop() {
// TODO: stopOffload().
mUpstreamLinkProperties = null;
mHwInterface.stopOffloadControl();
mControlInitialized = false;
mConfigInitialized = false;
}
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started()) return;
// TODO: setUpstreamParameters().
mUpstreamLinkProperties = lp;
}
// TODO: public void addDownStream(...)
private boolean started() {
return mConfigInitialized && mControlInitialized;
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2017 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.server.connectivity.tethering;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl.stopOffloadCallback;
import android.os.RemoteException;
import android.util.Log;
/**
* Capture tethering dependencies, for injection.
*
* @hide
*/
public class OffloadHardwareInterface {
private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
private static native boolean configOffload();
private IOffloadControl mOffloadControl;
public OffloadHardwareInterface() {}
public boolean initOffloadConfig() {
return configOffload();
}
// TODO: Extend this to take a TetheringControlCallback for registration.
public boolean initOffloadControl() {
if (mOffloadControl == null) {
try {
mOffloadControl = IOffloadControl.getService();
} catch (RemoteException e) {
Log.d(TAG, "tethering offload control not supported: " + e);
return false;
}
}
// TODO: call mOffloadControl.initOffload(...callback...);
return true;
}
public void stopOffloadControl() {
if (mOffloadControl == null) return;
try {
final stopOffloadCallback cb = new stopOffloadCallback() {
@Override
public void onValues(boolean success, String errMsg) {
if (success) return;
Log.e(TAG, "stopOffload failed: " + errMsg);
}
};
mOffloadControl.stopOffload(cb);
} catch (RemoteException e) {
Log.d(TAG, "failed to stopOffload: " + e);
}
mOffloadControl = null;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2017 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.server.connectivity.tethering;
/**
* Capture tethering dependencies, for injection.
*
* @hide
*/
public class TetheringDependencies {
public OffloadHardwareInterface getOffloadHardwareInterface() {
return new OffloadHardwareInterface();
}
}

View File

@@ -16,6 +16,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
@@ -58,6 +59,9 @@ LOCAL_SHARED_LIBRARIES += \
liblog \
libhardware \
libhardware_legacy \
libhidlbase \
libhidltransport \
libhwbinder \
libkeystore_binder \
libnativehelper \
libutils \
@@ -73,4 +77,5 @@ LOCAL_SHARED_LIBRARIES += \
libEGL \
libGLESv2 \
libnetutils \
android.hardware.tetheroffload.config@1.0 \

View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2017 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.
*/
#include <errno.h>
#include <error.h>
#include <hidl/HidlSupport.h>
#include <jni.h>
#include <JNIHelp.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <android-base/unique_fd.h>
#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
#define LOG_TAG "OffloadHardwareInterface"
#include <utils/Log.h>
namespace android {
using hardware::hidl_handle;
using hardware::hidl_string;
using hardware::tetheroffload::config::V1_0::IOffloadConfig;
namespace {
inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) {
return reinterpret_cast<const sockaddr *>(nladdr);
}
int conntrackSocket(unsigned groups) {
base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
if (s.get() < 0) return -errno;
const struct sockaddr_nl bind_addr = {
.nl_family = AF_NETLINK,
.nl_pad = 0,
.nl_pid = 0,
.nl_groups = groups,
};
if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) {
return -errno;
}
const struct sockaddr_nl kernel_addr = {
.nl_family = AF_NETLINK,
.nl_pad = 0,
.nl_pid = 0,
.nl_groups = groups,
};
if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
return -errno;
}
return s.release();
}
// Return a hidl_handle that owns the file descriptor owned by fd, and will
// auto-close it (otherwise there would be double-close problems).
//
// Rely upon the compiler to eliminate the constexprs used for clarity.
hidl_handle&& handleFromFileDescriptor(base::unique_fd fd) {
hidl_handle h;
NATIVE_HANDLE_DECLARE_STORAGE(storage, 0, 0);
static constexpr int kNumFds = 1;
static constexpr int kNumInts = 0;
native_handle_t *nh = native_handle_init(storage, kNumFds, kNumInts);
nh->data[0] = fd.release();
static constexpr bool kTakeOwnership = true;
h.setTo(nh, kTakeOwnership);
return std::move(h);
}
} // namespace
static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload(
JNIEnv* /* env */) {
sp<IOffloadConfig> configInterface = IOffloadConfig::getService();
if (configInterface.get() == nullptr) {
ALOGD("Could not find IOffloadConfig service.");
return false;
}
// Per the IConfigOffload definition:
//
// fd1 A file descriptor bound to the following netlink groups
// (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
//
// fd2 A file descriptor bound to the following netlink groups
// (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
base::unique_fd
fd1(conntrackSocket(NFNLGRP_CONNTRACK_NEW | NFNLGRP_CONNTRACK_DESTROY)),
fd2(conntrackSocket(NFNLGRP_CONNTRACK_UPDATE | NFNLGRP_CONNTRACK_DESTROY));
if (fd1.get() < 0 || fd2.get() < 0) {
ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
return false;
}
hidl_handle h1(handleFromFileDescriptor(std::move(fd1))),
h2(handleFromFileDescriptor(std::move(fd2)));
bool rval;
hidl_string msg;
configInterface->setHandles(h1, h2,
[&rval, &msg](bool success, const hidl_string& errMsg) {
rval = success;
msg = errMsg;
});
if (!rval) {
ALOGE("IOffloadConfig::setHandles() error: %s", msg.c_str());
}
return rval;
}
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "configOffload", "()Z",
(void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload },
};
int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) {
return jniRegisterNativeMethods(env,
"com/android/server/connectivity/tethering/OffloadHardwareInterface",
gMethods, NELEM(gMethods));
}
}; // namespace android

View File

@@ -40,6 +40,7 @@ int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GnssLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvUinputBridge(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -78,6 +79,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_location_GnssLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);

View File

@@ -56,6 +56,8 @@ import android.support.test.runner.AndroidJUnit4;
import android.telephony.CarrierConfigManager;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.connectivity.tethering.OffloadHardwareInterface;
import com.android.server.connectivity.tethering.TetheringDependencies;
import org.junit.After;
import org.junit.Before;
@@ -78,7 +80,9 @@ public class TetheringTest {
@Mock private INetworkStatsService mStatsService;
@Mock private INetworkPolicyManager mPolicyManager;
@Mock private MockableSystemProperties mSystemProperties;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
@Mock private TetheringDependencies mTetheringDependencies;
@Mock private UsbManager mUsbManager;
@Mock private WifiManager mWifiManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@@ -138,8 +142,11 @@ public class TetheringTest {
};
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
when(mTetheringDependencies.getOffloadHardwareInterface())
.thenReturn(mOffloadHardwareInterface);
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties);
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
}
@After