diff options
author | 2017-05-17 04:17:25 +0000 | |
---|---|---|
committer | 2017-05-17 04:17:33 +0000 | |
commit | 95a01b99f55a77fb1d5b38c989332ba2a38d34e7 (patch) | |
tree | ca9b5989406e23702b99d312e869ca80f08bc88c | |
parent | 380fdadca30855cf1729fb936fab090304e57518 (diff) | |
parent | 58ed1b051bdffd239d92919170a0bb41a4cc197c (diff) |
Merge "Add tethering offload HAL call via JNI"
10 files changed, 314 insertions, 12 deletions
diff --git a/services/core/Android.mk b/services/core/Android.mk index 20a699b180b7..4d080e9d6103 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -31,6 +31,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android.hardware.weaver-V1.0-java-static \ android.hardware.biometrics.fingerprint-V2.1-java-static \ android.hardware.oemlock-V1.0-java-static \ + android.hardware.tetheroffload.control-V1.0-java-static \ android.hardware.vibrator-V1.0-java-constants \ ifneq ($(INCREMENTAL_BUILDS),) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 688c231328c8..6c35d5671b10 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -139,6 +139,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; @@ -789,8 +790,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); @@ -840,6 +840,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(); diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 925dfb50797d..b14cbc8658c8 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -84,6 +84,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; @@ -181,7 +182,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; @@ -197,7 +199,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<>(); @@ -1491,7 +1494,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; } diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java index 220e7514facc..6c93730974d4 100644 --- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java +++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java @@ -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; + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java new file mode 100644 index 000000000000..87fc491b0bdd --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java new file mode 100644 index 000000000000..be2cf080b330 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -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(); + } +} diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 675b64103e81..84ab48de147c 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.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 \ @@ -63,6 +64,7 @@ LOCAL_SHARED_LIBRARIES += \ liblog \ libhardware \ libhardware_legacy \ + libhidlbase \ libkeystore_binder \ libnativehelper \ libutils \ @@ -94,6 +96,7 @@ LOCAL_SHARED_LIBRARIES += \ android.hardware.light@2.0 \ android.hardware.power@1.0 \ android.hardware.power@1.1 \ + android.hardware.tetheroffload.config@1.0 \ android.hardware.thermal@1.0 \ android.hardware.tv.cec@1.0 \ android.hardware.tv.input@1.0 \ diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp new file mode 100644 index 000000000000..241ccf6ed166 --- /dev/null +++ b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp @@ -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 diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 79c9b417e42a..c3617e055320 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -42,6 +42,7 @@ int register_android_server_VibratorService(JNIEnv* env); int register_android_server_location_ContextHubService(JNIEnv* env); int register_android_server_location_GnssLocationProvider(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); @@ -84,6 +85,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_location_ContextHubService(env); register_android_server_location_GnssLocationProvider(env); register_android_server_connectivity_Vpn(env); + register_android_server_connectivity_tethering_OffloadHardwareInterface(env); register_android_server_ConsumerIrService(env); register_android_server_BatteryStatsService(env); register_android_server_hdmi_HdmiCecController(env); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 3172c6ec856a..bc89c0f4f71f 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -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 |