From d8676d99ff7bfb69c11d5db2abd206002ec54cee Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 23 Oct 2019 16:27:52 +0800 Subject: [PATCH 1/3] [Tether07] Clean up build rule for libtetheroffloadjni - Statically include android.hardware.tetheroffload.config@1.0, libcutils and their dependency library. - Use shared-lib if there is NDK or NDK-compliant version - Remove android.hardware.tetheroffload.control-V1.0-java from service.core because it is already statically built in tethering apk Bug: 143195885 Test: -build, flash, boot Change-Id: Ic082045bc04d3989f7f095c7a499bc0d943e4031 Merged-In: Ic082045bc04d3989f7f095c7a499bc0d943e4031 --- packages/Tethering/Android.bp | 21 ++++++++++--- packages/Tethering/CleanSpec.mk | 52 +++++++++++++++++++++++++++++++++ services/core/Android.bp | 1 - 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 packages/Tethering/CleanSpec.mk diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 7b35f4d56a7a4..cd51f5f90c346 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -41,20 +41,26 @@ android_library { defaults: ["TetheringAndroidLibraryDefaults"], } -cc_library_shared { +// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK). +cc_library { name: "libtetheroffloadjni", srcs: [ "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", ], shared_libs: [ - "libnativehelper", - "libcutils", - "android.hardware.tetheroffload.config@1.0", + "libcgrouprc", + "libnativehelper_compat_libc++", + "libvndksupport", ], static_libs: [ + "android.hardware.tetheroffload.config@1.0", "liblog", "libbase", + "libbinderthreadstate", + "libcutils", "libhidlbase", + "libjsoncpp", + "libprocessgroup", "libutils", ], @@ -64,6 +70,8 @@ cc_library_shared { "-Wno-unused-parameter", "-Wthread-safety", ], + + ldflags: ["-Wl,--exclude-libs=ALL,-error-limit=0"], } // Common defaults for compiling the actual APK. @@ -71,7 +79,12 @@ java_defaults { name: "TetheringAppDefaults", platform_apis: true, privileged: true, + // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies + // explicitly. jni_libs: [ + "libcgrouprc", + "libnativehelper_compat_libc++", + "libvndksupport", "libtetheroffloadjni", ], resource_dirs: [ diff --git a/packages/Tethering/CleanSpec.mk b/packages/Tethering/CleanSpec.mk new file mode 100644 index 0000000000000..70db351a69287 --- /dev/null +++ b/packages/Tethering/CleanSpec.mk @@ -0,0 +1,52 @@ +# Copyright (C) 2019 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Tethering) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/InProcessTethering) + +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/services/core/Android.bp b/services/core/Android.bp index 084a74724ad85..4900781d6df52 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -50,7 +50,6 @@ java_library_static { "android.hardware.biometrics.face-V1.0-java", "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.oemlock-V1.0-java", - "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.configstore-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hidl.manager-V1.2-java", From 0df2ebc43de508980c096346a7f70a0653779361 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 30 Sep 2019 14:40:57 +0800 Subject: [PATCH 2/3] [Tether07] Migrate Tethering into module Now tethering would be run in dedicated service. TetheringManager is the interface used to communicate with TetheringService. The new call flow would be: ConnectivityManager -> ConnectivityService -> TetheringManager -> TetheringService. Note: the return value of #tether(), #untether() and #setUsbTethering() APIs would always be no error. Client can use #getLastTetherError() or #getTetheredIfaces or listen tether state change to check status of corresponding interface. Bug: 136040414 Bug: 144742179 Test: -build, flash, boot -atest TetheringTests -atest FrameworksNetTests Change-Id: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3 Merged-In: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3 --- core/java/android/os/ResultReceiver.aidl | 2 +- packages/Tethering/Android.bp | 49 +- packages/Tethering/AndroidManifest.xml | 6 + .../Tethering/AndroidManifest_InProcess.xml | 35 ++ .../Tethering/common/TetheringLib/Android.bp | 13 +- .../android/net/ITetherInternalCallback.aidl | 34 ++ .../src/android/net/ITetheringConnector.aidl | 17 + .../src/android/net/TetherStatesParcel.aidl | 31 ++ .../net/TetheringConfigurationParcel.aidl | 37 ++ .../src/android/net/TetheringManager.java | 507 ++++++++++++++++++ ...ity_tethering_OffloadHardwareInterface.cpp | 14 + .../BaseNetdUnsolicitedEventListener.java | 70 +++ .../net/util/VersionedBroadcastListener.java | 13 +- .../tethering/EntitlementManager.java | 19 +- .../tethering/IPv6TetheringCoordinator.java | 27 +- .../tethering/OffloadHardwareInterface.java | 2 + .../connectivity/tethering}/Tethering.java | 283 ++++++---- .../tethering/TetheringConfiguration.java | 29 + .../tethering/TetheringDependencies.java | 61 ++- .../tethering/TetheringInterfaceUtils.java | 0 .../tethering/TetheringService.java | 178 ++++++ packages/Tethering/tests/unit/Android.bp | 15 - .../util/VersionedBroadcastListenerTest.java | 6 +- .../tethering/EntitlementManagerTest.java | 45 +- .../tethering}/TetheringTest.java | 253 ++++++--- services/core/Android.bp | 9 - .../android/server/ConnectivityService.java | 85 ++- .../server/net/NetworkStatsService.java | 1 - services/core/jni/Android.bp | 2 - services/core/jni/onload.cpp | 2 - .../java/com/android/server/SystemServer.java | 10 + services/net/Android.bp | 2 +- tests/net/Android.bp | 1 - .../ConnectivityServiceIntegrationTest.kt | 5 +- .../server/ConnectivityServiceTest.java | 4 +- 35 files changed, 1503 insertions(+), 364 deletions(-) create mode 100644 packages/Tethering/AndroidManifest_InProcess.xml create mode 100644 packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl create mode 100644 packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl create mode 100644 packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl create mode 100644 packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java create mode 100644 packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java rename {services/net/java => packages/Tethering/src}/android/net/util/VersionedBroadcastListener.java (91%) rename {services/core/java => packages/Tethering/src}/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java (93%) rename {services/core/java/com/android/server/connectivity => packages/Tethering/src/com/android/server/connectivity/tethering}/Tethering.java (91%) rename {services/core/java => packages/Tethering/src}/com/android/server/connectivity/tethering/TetheringDependencies.java (59%) rename {services/core/java => packages/Tethering/src}/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java (100%) create mode 100644 packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java rename {tests/net/java => packages/Tethering/tests/unit/src}/android/net/util/VersionedBroadcastListenerTest.java (97%) rename {tests/net/java/com/android/server/connectivity => packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering}/TetheringTest.java (86%) diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl index 28ce6d5f15b03..1ea6b43043d69 100644 --- a/core/java/android/os/ResultReceiver.aidl +++ b/core/java/android/os/ResultReceiver.aidl @@ -17,4 +17,4 @@ package android.os; -parcelable ResultReceiver; +@JavaOnlyStableParcelable parcelable ResultReceiver; diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index cd51f5f90c346..7e8721d3cc70e 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -22,13 +22,12 @@ java_defaults { ":framework-tethering-shared-srcs", ":net-module-utils-srcs", ":services-tethering-shared-srcs", - ":servicescore-tethering-src", ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-java", + "netd_aidl_interface-unstable-java", "netlink-client", - "networkstack-aidl-interfaces-java", + "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.control-V1.0-java", "tethering-client", ], @@ -96,7 +95,16 @@ java_defaults { } // Non-updatable tethering running in the system server process for devices not using the module -// TODO: build in-process tethering APK here. +android_app { + name: "InProcessTethering", + defaults: ["TetheringAppDefaults"], + static_libs: ["TetheringApiCurrentLib"], + certificate: "platform", + manifest: "AndroidManifest_InProcess.xml", + // InProcessTethering is a replacement for Tethering + overrides: ["Tethering"], + // TODO: use PlatformNetworkPermissionConfig. +} // Updatable tethering packaged as an application android_app { @@ -109,36 +117,3 @@ android_app { // The permission configuration *must* be included to ensure security of the device required: ["NetworkPermissionConfig"], } - -// This group will be removed when tethering migration is done. -filegroup { - name: "tethering-servicescore-srcs", - srcs: [ - "src/com/android/server/connectivity/tethering/EntitlementManager.java", - "src/com/android/server/connectivity/tethering/OffloadController.java", - "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java", - "src/com/android/server/connectivity/tethering/TetheringConfiguration.java", - "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java", - ], -} - -// This group will be removed when tethering migration is done. -filegroup { - name: "tethering-servicesnet-srcs", - srcs: [ - "src/android/net/dhcp/DhcpServerCallbacks.java", - "src/android/net/dhcp/DhcpServingParamsParcelExt.java", - "src/android/net/ip/IpServer.java", - "src/android/net/ip/RouterAdvertisementDaemon.java", - "src/android/net/util/InterfaceSet.java", - "src/android/net/util/PrefixUtils.java", - ], -} - -// This group would be removed when tethering migration is done. -filegroup { - name: "tethering-jni-srcs", - srcs: [ - "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", - ], -} diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index eb51593e45382..1430ed00aa913 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -25,5 +25,11 @@ android:process="com.android.networkstack.process" android:extractNativeLibs="false" android:persistent="true"> + + + + + diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml new file mode 100644 index 0000000000000..28d405c3133a7 --- /dev/null +++ b/packages/Tethering/AndroidManifest_InProcess.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 5b01b1e038c35..adc5a723a9607 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -18,8 +18,12 @@ aidl_interface { name: "tethering-aidl-interfaces", local_include_dir: "src", + include_dirs: ["frameworks/base/core/java"], // For framework parcelables. srcs: [ + "src/android/net/ITetherInternalCallback.aidl", "src/android/net/ITetheringConnector.aidl", + "src/android/net/TetheringConfigurationParcel.aidl", + "src/android/net/TetherStatesParcel.aidl", ], backend: { ndk: { @@ -33,8 +37,15 @@ aidl_interface { java_library { name: "tethering-client", - platform_apis: true, + sdk_version: "system_current", static_libs: [ "tethering-aidl-interfaces-java", ], } + +// This is temporary file group which would be removed after TetheringManager is built +// into tethering-client. Will be done by aosp/1156906. +filegroup { + name: "tethering-manager", + srcs: ["src/android/net/TetheringManager.java"], +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl new file mode 100644 index 0000000000000..abb00e819f50c --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 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 android.net; + +import android.net.Network; +import android.net.TetheringConfigurationParcel; +import android.net.TetherStatesParcel; + +/** + * Callback class for receiving tethering changed events + * @hide + */ +oneway interface ITetherInternalCallback +{ + void onUpstreamChanged(in Network network); + void onConfigurationChanged(in TetheringConfigurationParcel config); + void onTetherStatesChanged(in TetherStatesParcel states); + void onCallbackCreated(in Network network, in TetheringConfigurationParcel config, + in TetherStatesParcel states); +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index 443481e33f8d8..bfe502fbeb11a 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -15,6 +15,23 @@ */ package android.net; +import android.net.ITetherInternalCallback; +import android.os.ResultReceiver; + /** @hide */ oneway interface ITetheringConnector { + void tether(String iface); + + void untether(String iface); + + void setUsbTethering(boolean enable); + + void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi); + + void stopTethering(int type); + + void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, + boolean showEntitlementUi); + + void registerTetherInternalCallback(ITetherInternalCallback callback); } diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl new file mode 100644 index 0000000000000..3d842b3374284 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 android.net; + +/** + * Status details for tethering downstream interfaces. + * {@hide} + */ +parcelable TetherStatesParcel { + String[] availableList; + String[] tetheredList; + String[] localOnlyList; + String[] erroredIfaceList; + // List of Last error code corresponding to each errored iface in erroredIfaceList. */ + // TODO: Improve this as b/143122247. + int[] lastErrorList; +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl new file mode 100644 index 0000000000000..fdf0d16057b3c --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 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 android.net; + +/** + * Configuration details for a tethering. + * @hide + */ +parcelable TetheringConfigurationParcel { + int subId; + String[] tetherableUsbRegexs; + String[] tetherableWifiRegexs; + String[] tetherableBluetoothRegexs; + boolean isDunRequired; + boolean chooseUpstreamAutomatically; + int[] preferredUpstreamIfaceTypes; + String[] legacyDhcpRanges; + String[] defaultIPv4DNS; + boolean enableLegacyDhcpServer; + String[] provisioningApp; + String provisioningAppNoUi; + int provisioningCheckPeriod; +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java new file mode 100644 index 0000000000000..9e8726edf0e18 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2019 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 android.net; + +import static android.Manifest.permission.NETWORK_STACK; +import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.util.SharedLog; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.util.StringJoiner; + +/** + * Service used to communicate with the tethering, which is running in a separate module. + * @hide + */ +public class TetheringManager { + private static final String TAG = TetheringManager.class.getSimpleName(); + + private static TetheringManager sInstance; + + @Nullable + private ITetheringConnector mConnector; + private TetherInternalCallback mCallback; + private Network mTetherUpstream; + private TetheringConfigurationParcel mTetheringConfiguration; + private TetherStatesParcel mTetherStatesParcel; + + private final RemoteCallbackList mTetheringEventCallbacks = + new RemoteCallbackList<>(); + @GuardedBy("mLog") + private final SharedLog mLog = new SharedLog(TAG); + + private TetheringManager() { } + + /** + * Get the TetheringManager singleton instance. + */ + public static synchronized TetheringManager getInstance() { + if (sInstance == null) { + sInstance = new TetheringManager(); + } + return sInstance; + } + + private class TetheringConnection implements + ConnectivityModuleConnector.ModuleServiceCallback { + @Override + public void onModuleServiceConnected(@NonNull IBinder service) { + logi("Tethering service connected"); + registerTetheringService(service); + } + } + + private void registerTetheringService(@NonNull IBinder service) { + final ITetheringConnector connector = ITetheringConnector.Stub.asInterface(service); + + log("Tethering service registered"); + + // Currently TetheringManager instance is only used by ConnectivityService and mConnector + // only expect to assign once when system server start and bind tethering service. + // STOPSHIP: Change mConnector to final before TetheringManager put into boot classpath. + mConnector = connector; + mCallback = new TetherInternalCallback(); + try { + mConnector.registerTetherInternalCallback(mCallback); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + private class TetherInternalCallback extends ITetherInternalCallback.Stub { + private final ConditionVariable mWaitForCallback = new ConditionVariable(false); + private static final int EVENT_CALLBACK_TIMEOUT_MS = 60_000; + + @Override + public void onUpstreamChanged(Network network) { + mTetherUpstream = network; + reportUpstreamChanged(network); + } + + @Override + public void onConfigurationChanged(TetheringConfigurationParcel config) { + mTetheringConfiguration = config; + } + + @Override + public void onTetherStatesChanged(TetherStatesParcel states) { + mTetherStatesParcel = states; + } + + @Override + public void onCallbackCreated(Network network, TetheringConfigurationParcel config, + TetherStatesParcel states) { + mTetherUpstream = network; + mTetheringConfiguration = config; + mTetherStatesParcel = states; + mWaitForCallback.open(); + } + + boolean awaitCallbackCreation() { + return mWaitForCallback.block(EVENT_CALLBACK_TIMEOUT_MS); + } + } + + private void reportUpstreamChanged(Network network) { + final int length = mTetheringEventCallbacks.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + try { + mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + } finally { + mTetheringEventCallbacks.finishBroadcast(); + } + } + + /** + * Start the tethering service. Should be called only once on device startup. + * + *

This method will start the tethering service either in the network stack process, + * or inside the system server on devices that do not support the tethering module. + * + * {@hide} + */ + public void start() { + // Using MAINLINE_NETWORK_STACK permission after cutting off the dpendency of system server. + ConnectivityModuleConnector.getInstance().startModuleService( + ITetheringConnector.class.getName(), NETWORK_STACK, + new TetheringConnection()); + log("Tethering service start requested"); + } + + /** + * Attempt to tether the named interface. This will setup a dhcp server + * on the interface, forward and NAT IP v4 packets and forward DNS requests + * to the best active upstream network interface. Note that if no upstream + * IP network interface is available, dhcp will still run and traffic will be + * allowed between the tethered devices and this device, though upstream net + * access will of course fail until an upstream network interface becomes + * active. Note: return value do not have any meaning. It is better to use + * #getTetherableIfaces() to ensure corresponding interface is available for + * tethering before calling #tether(). + * + * TODO: Deprecate this API. The only usages should be in PanService and Wifi P2P which + * need direct access. + * + * {@hide} + */ + public int tether(@NonNull String iface) { + try { + mConnector.tether(iface); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return TETHER_ERROR_NO_ERROR; + } + + /** + * Stop tethering the named interface. + * + * {@hide} + */ + public int untether(@NonNull String iface) { + try { + mConnector.untether(iface); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return TETHER_ERROR_NO_ERROR; + } + + /** + * Attempt to both alter the mode of USB and Tethering of USB. WARNING: New client should not + * use this API anymore. All clients should use #startTethering or #stopTethering which + * encapsulate proper entitlement logic. If the API is used and an entitlement check is needed, + * downstream USB tethering will be enabled but will not have any upstream. + * + * @Deprecated + * {@hide} + */ + public int setUsbTethering(boolean enable) { + try { + mConnector.setUsbTethering(enable); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return TETHER_ERROR_NO_ERROR; + } + + /** + * Starts tethering and runs tether provisioning for the given type if needed. If provisioning + * fails, stopTethering will be called automatically. + * + * {@hide} + */ + // TODO: improve the usage of ResultReceiver, b/145096122 + public void startTethering(int type, @NonNull ResultReceiver receiver, + boolean showProvisioningUi) { + try { + mConnector.startTethering(type, receiver, showProvisioningUi); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if + * applicable. + * + * {@hide} + */ + public void stopTethering(int type) { + try { + mConnector.stopTethering(type); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Request the latest value of the tethering entitlement check. + * + * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns + * out some such apps are observed to abuse this API, change to per-UID limits on this API + * if it's really needed. + */ + // TODO: improve the usage of ResultReceiver, b/145096122 + public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver, + boolean showEntitlementUi) { + try { + mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Register tethering event callback. + * + * {@hide} + */ + public void registerTetheringEventCallback(@NonNull ITetheringEventCallback callback) { + mTetheringEventCallbacks.register(callback); + } + + /** + * Unregister tethering event callback. + * + * {@hide} + */ + public void unregisterTetheringEventCallback(@NonNull ITetheringEventCallback callback) { + mTetheringEventCallbacks.unregister(callback); + } + + /** + * Get a more detailed error code after a Tethering or Untethering + * request asynchronously failed. + * + * {@hide} + */ + public int getLastTetherError(@NonNull String iface) { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR; + + int i = 0; + for (String errored : mTetherStatesParcel.erroredIfaceList) { + if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i]; + + i++; + } + return TETHER_ERROR_NO_ERROR; + } + + /** + * Get the list of regular expressions that define any tetherable + * USB network interfaces. If USB tethering is not supported by the + * device, this list should be empty. + * + * {@hide} + */ + public @NonNull String[] getTetherableUsbRegexs() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + return mTetheringConfiguration.tetherableUsbRegexs; + } + + /** + * Get the list of regular expressions that define any tetherable + * Wifi network interfaces. If Wifi tethering is not supported by the + * device, this list should be empty. + * + * {@hide} + */ + public @NonNull String[] getTetherableWifiRegexs() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + return mTetheringConfiguration.tetherableWifiRegexs; + } + + /** + * Get the list of regular expressions that define any tetherable + * Bluetooth network interfaces. If Bluetooth tethering is not supported by the + * device, this list should be empty. + * + * {@hide} + */ + public @NonNull String[] getTetherableBluetoothRegexs() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + return mTetheringConfiguration.tetherableBluetoothRegexs; + } + + /** + * Get the set of tetherable, available interfaces. This list is limited by + * device configuration and current interface existence. + * + * {@hide} + */ + public @NonNull String[] getTetherableIfaces() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.availableList; + } + + /** + * Get the set of tethered interfaces. + * + * {@hide} + */ + public @NonNull String[] getTetheredIfaces() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.tetheredList; + } + + /** + * Get the set of interface names which attempted to tether but + * failed. + * + * {@hide} + */ + public @NonNull String[] getTetheringErroredIfaces() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.erroredIfaceList; + } + + /** + * Get the set of tethered dhcp ranges. + * + * {@hide} + */ + public @NonNull String[] getTetheredDhcpRanges() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + return mTetheringConfiguration.legacyDhcpRanges; + } + + /** + * Check if the device allows for tethering. + * + * {@hide} + */ + public boolean hasTetherableConfiguration() { + if (!mCallback.awaitCallbackCreation()) { + throw new NullPointerException("callback was not ready yet"); + } + final boolean hasDownstreamConfiguration = + (mTetheringConfiguration.tetherableUsbRegexs.length != 0) + || (mTetheringConfiguration.tetherableWifiRegexs.length != 0) + || (mTetheringConfiguration.tetherableBluetoothRegexs.length != 0); + final boolean hasUpstreamConfiguration = + (mTetheringConfiguration.preferredUpstreamIfaceTypes.length != 0) + || mTetheringConfiguration.chooseUpstreamAutomatically; + + return hasDownstreamConfiguration && hasUpstreamConfiguration; + } + + /** + * Log a message in the local log. + */ + private void log(@NonNull String message) { + synchronized (mLog) { + mLog.log(message); + } + } + + /** + * Log a condition that should never happen. + */ + private void logWtf(@NonNull String message, @Nullable Throwable e) { + Slog.wtf(TAG, message); + synchronized (mLog) { + mLog.e(message, e); + } + } + + /** + * Log a ERROR level message in the local and system logs. + */ + private void loge(@NonNull String message, @Nullable Throwable e) { + synchronized (mLog) { + mLog.e(message, e); + } + } + + /** + * Log a INFO level message in the local and system logs. + */ + private void logi(@NonNull String message) { + synchronized (mLog) { + mLog.i(message); + } + } + + /** + * Dump TetheringManager logs to the specified {@link PrintWriter}. + */ + public void dump(@NonNull PrintWriter pw) { + // dump is thread-safe on SharedLog + mLog.dump(null, pw, null); + + pw.print("subId: "); + pw.println(mTetheringConfiguration.subId); + + dumpStringArray(pw, "tetherableUsbRegexs", + mTetheringConfiguration.tetherableUsbRegexs); + dumpStringArray(pw, "tetherableWifiRegexs", + mTetheringConfiguration.tetherableWifiRegexs); + dumpStringArray(pw, "tetherableBluetoothRegexs", + mTetheringConfiguration.tetherableBluetoothRegexs); + + pw.print("isDunRequired: "); + pw.println(mTetheringConfiguration.isDunRequired); + + pw.print("chooseUpstreamAutomatically: "); + pw.println(mTetheringConfiguration.chooseUpstreamAutomatically); + + dumpStringArray(pw, "legacyDhcpRanges", mTetheringConfiguration.legacyDhcpRanges); + dumpStringArray(pw, "defaultIPv4DNS", mTetheringConfiguration.defaultIPv4DNS); + + dumpStringArray(pw, "provisioningApp", mTetheringConfiguration.provisioningApp); + pw.print("provisioningAppNoUi: "); + pw.println(mTetheringConfiguration.provisioningAppNoUi); + + pw.print("enableLegacyDhcpServer: "); + pw.println(mTetheringConfiguration.enableLegacyDhcpServer); + + pw.println(); + } + + private static void dumpStringArray(@NonNull PrintWriter pw, @NonNull String label, + @Nullable String[] values) { + pw.print(label); + pw.print(": "); + + if (values != null) { + final StringJoiner sj = new StringJoiner(", ", "[", "]"); + for (String value : values) sj.add(value); + + pw.print(sj.toString()); + } else { + pw.print("null"); + } + + pw.println(); + } +} diff --git a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp index 3eaf48845a2fd..663154a490481 100644 --- a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp +++ b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp @@ -145,4 +145,18 @@ int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIE gMethods, NELEM(gMethods)); } +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_android_server_connectivity_tethering_OffloadHardwareInterface(env) < 0) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} + }; // namespace android diff --git a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java new file mode 100644 index 0000000000000..3218c0b387bb4 --- /dev/null +++ b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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 android.net.util; + +import android.net.INetdUnsolicitedEventListener; + +import androidx.annotation.NonNull; + +/** + * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be + * overridden. + */ +public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { + + @Override + public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, + int uid) { } + + @Override + public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { } + + @Override + public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS, + @NonNull String[] servers) { } + + @Override + public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags, + int scope) { } + + @Override + public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags, + int scope) { } + + @Override + public void onInterfaceAdded(@NonNull String ifName) { } + + @Override + public void onInterfaceRemoved(@NonNull String ifName) { } + + @Override + public void onInterfaceChanged(@NonNull String ifName, boolean up) { } + + @Override + public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { } + + @Override + public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway, + @NonNull String ifName) { } + + @Override + public void onStrictCleartextDetected(int uid, @NonNull String hex) { } + + @Override + public int getInterfaceVersion() { + return INetdUnsolicitedEventListener.VERSION; + } +} diff --git a/services/net/java/android/net/util/VersionedBroadcastListener.java b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java similarity index 91% rename from services/net/java/android/net/util/VersionedBroadcastListener.java rename to packages/Tethering/src/android/net/util/VersionedBroadcastListener.java index 107c40495f9ef..e2804abd752bb 100644 --- a/services/net/java/android/net/util/VersionedBroadcastListener.java +++ b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java @@ -39,10 +39,6 @@ import java.util.function.Consumer; public class VersionedBroadcastListener { private static final boolean DBG = false; - public interface IntentCallback { - public void run(Intent intent); - } - private final String mTag; private final Context mContext; private final Handler mHandler; @@ -61,6 +57,7 @@ public class VersionedBroadcastListener { mGenerationNumber = new AtomicInteger(0); } + /** Start listening to intent broadcast. */ public void startListening() { if (DBG) Log.d(mTag, "startListening"); if (mReceiver != null) return; @@ -69,6 +66,7 @@ public class VersionedBroadcastListener { mContext.registerReceiver(mReceiver, mFilter, null, mHandler); } + /** Stop listening to intent broadcast. */ public void stopListening() { if (DBG) Log.d(mTag, "stopListening"); if (mReceiver == null) return; @@ -85,8 +83,7 @@ public class VersionedBroadcastListener { // Used to verify this receiver is still current. public final int generationNumber; - public Receiver( - String tag, AtomicInteger atomicGenerationNumber, Consumer callback) { + Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer callback) { this.tag = tag; this.atomicGenerationNumber = atomicGenerationNumber; this.callback = callback; @@ -98,8 +95,8 @@ public class VersionedBroadcastListener { final int currentGenerationNumber = atomicGenerationNumber.get(); if (DBG) { - Log.d(tag, "receiver generationNumber=" + generationNumber + - ", current generationNumber=" + currentGenerationNumber); + Log.d(tag, "receiver generationNumber=" + generationNumber + + ", current generationNumber=" + currentGenerationNumber); } if (generationNumber != currentGenerationNumber) return; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index 6b0f1de7ce859..ba5d08dce4cac 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -47,6 +47,7 @@ import android.os.Parcel; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.telephony.CarrierConfigManager; @@ -55,7 +56,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; -import com.android.server.connectivity.MockableSystemProperties; import java.io.PrintWriter; @@ -94,7 +94,6 @@ public class EntitlementManager { private final ArraySet mCurrentTethers; private final Context mContext; private final int mPermissionChangeMessageCode; - private final MockableSystemProperties mSystemProperties; private final SharedLog mLog; private final SparseIntArray mEntitlementCacheValue; private final EntitlementHandler mHandler; @@ -110,12 +109,12 @@ public class EntitlementManager { private TetheringConfigurationFetcher mFetcher; public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log, - int permissionChangeMessageCode, MockableSystemProperties systemProperties) { + int permissionChangeMessageCode) { + mContext = ctx; mLog = log.forSubComponent(TAG); mCurrentTethers = new ArraySet(); mCellularPermitted = new SparseIntArray(); - mSystemProperties = systemProperties; mEntitlementCacheValue = new SparseIntArray(); mTetherMasterSM = tetherMasterSM; mPermissionChangeMessageCode = permissionChangeMessageCode; @@ -287,7 +286,7 @@ public class EntitlementManager { */ @VisibleForTesting protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) { - if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false) + if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false) || config.provisioningApp.length == 0) { return false; } @@ -526,8 +525,8 @@ public class EntitlementManager { handleMaybeRunProvisioning(config); break; case EVENT_GET_ENTITLEMENT_VALUE: - handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj, - toBool(msg.arg2)); + handleRequestLatestTetheringEntitlementValue(msg.arg1, + (ResultReceiver) msg.obj, toBool(msg.arg2)); break; default: mLog.log("Unknown event: " + msg.what); @@ -651,15 +650,15 @@ public class EntitlementManager { } /** Get the last value of the tethering entitlement check. */ - public void getLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver, + public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver, boolean showEntitlementUi) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE, downstream, encodeBool(showEntitlementUi), receiver)); } - private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver, - boolean showEntitlementUi) { + private void handleRequestLatestTetheringEntitlementValue(int downstream, + ResultReceiver receiver, boolean showEntitlementUi) { final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); if (!isTetherProvisioningRequired(config)) { receiver.send(TETHER_ERROR_NO_ERROR, null); diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java similarity index 93% rename from services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java rename to packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java index 81863439c0171..edfe3cad90395 100644 --- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java @@ -82,6 +82,7 @@ public class IPv6TetheringCoordinator { mNextSubnetId = 0; } + /** Add active downstream to ipv6 tethering candidate list. */ public void addActiveDownstream(IpServer downstream, int mode) { if (findDownstream(downstream) == null) { // Adding a new downstream appends it to the list. Adding a @@ -97,6 +98,7 @@ public class IPv6TetheringCoordinator { } } + /** Remove downstream from ipv6 tethering candidate list. */ public void removeActiveDownstream(IpServer downstream) { stopIPv6TetheringOn(downstream); if (mActiveDownstreams.remove(findDownstream(downstream))) { @@ -112,6 +114,11 @@ public class IPv6TetheringCoordinator { } } + /** + * Call when upstream NetworkState may be changed. + * If upstream has ipv6 for tethering, update this new NetworkState + * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces. + */ public void updateUpstreamNetworkState(NetworkState ns) { if (VDBG) { Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); @@ -122,8 +129,8 @@ public class IPv6TetheringCoordinator { return; } - if (mUpstreamNetworkState != null && - !ns.network.equals(mUpstreamNetworkState.network)) { + if (mUpstreamNetworkState != null + && !ns.network.equals(mUpstreamNetworkState.network)) { stopIPv6TetheringOnAllInterfaces(); } @@ -221,8 +228,8 @@ public class IPv6TetheringCoordinator { for (RouteInfo routeInfo : lp.getRoutes()) { final IpPrefix destination = routeInfo.getDestination(); - if ((destination.getAddress() instanceof Inet6Address) && - (destination.getPrefixLength() <= 64)) { + if ((destination.getAddress() instanceof Inet6Address) + && (destination.getPrefixLength() <= 64)) { v6only.addRoute(routeInfo); } } @@ -242,12 +249,12 @@ public class IPv6TetheringCoordinator { // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we // announce our own IPv6 address as DNS server. private static boolean isIPv6GlobalAddress(InetAddress ip) { - return (ip instanceof Inet6Address) && - !ip.isAnyLocalAddress() && - !ip.isLoopbackAddress() && - !ip.isLinkLocalAddress() && - !ip.isSiteLocalAddress() && - !ip.isMulticastAddress(); + return (ip instanceof Inet6Address) + && !ip.isAnyLocalAddress() + && !ip.isLoopbackAddress() + && !ip.isLinkLocalAddress() + && !ip.isSiteLocalAddress() + && !ip.isMulticastAddress(); } private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) { diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java index 01339a4a2c33d..00a677338b1b0 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -107,6 +107,8 @@ public class OffloadHardwareInterface { public OffloadHardwareInterface(Handler h, SharedLog log) { mHandler = h; mLog = log.forSubComponent(TAG); + + System.loadLibrary("tetheroffloadjni"); } /** Get default value indicating whether offload is supported. */ diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java similarity index 91% rename from services/core/java/com/android/server/connectivity/Tethering.java rename to packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index acedc36357301..058fb4fe98ca8 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity; +package com.android.server.connectivity.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -47,8 +47,6 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.ConnectivityService.SHORT_ARG; - import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -62,9 +60,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; +import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.ITetheringEventCallback; +import android.net.ITetherInternalCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -72,7 +71,10 @@ import android.net.Network; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkUtils; +import android.net.TetherStatesParcel; +import android.net.TetheringConfigurationParcel; import android.net.ip.IpServer; +import android.net.util.BaseNetdUnsolicitedEventListener; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; @@ -87,7 +89,6 @@ import android.os.Handler; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; @@ -111,14 +112,6 @@ import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.LocalServices; -import com.android.server.connectivity.tethering.EntitlementManager; -import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; -import com.android.server.connectivity.tethering.OffloadController; -import com.android.server.connectivity.tethering.TetheringConfiguration; -import com.android.server.connectivity.tethering.TetheringDependencies; -import com.android.server.connectivity.tethering.TetheringInterfaceUtils; -import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; -import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -127,32 +120,32 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; /** - * @hide * * This class holds much of the business logic to allow Android devices * to act as IP gateways via USB, BT, and WiFi interfaces. */ -public class Tethering extends BaseNetworkObserver { +public class Tethering { - private final static String TAG = Tethering.class.getSimpleName(); - private final static boolean DBG = false; - private final static boolean VDBG = false; + private static final String TAG = Tethering.class.getSimpleName(); + private static final boolean DBG = false; + private static final boolean VDBG = false; - private static final Class[] messageClasses = { + private static final Class[] sMessageClasses = { Tethering.class, TetherMasterSM.class, IpServer.class }; private static final SparseArray sMagicDecoderRing = - MessageUtils.findMessageNames(messageClasses); + MessageUtils.findMessageNames(sMessageClasses); private static class TetherState { public final IpServer ipServer; public int lastState; public int lastError; - public TetherState(IpServer ipServer) { + TetherState(IpServer ipServer) { this.ipServer = ipServer; // Assume all state machines start out available and with no errors. lastState = IpServer.STATE_AVAILABLE; @@ -177,6 +170,7 @@ public class Tethering extends BaseNetworkObserver { private final Context mContext; private final ArrayMap mTetherStates; private final BroadcastReceiver mStateReceiver; + // Stopship: replace mNMService before production. private final INetworkManagementService mNMService; private final INetworkStatsService mStatsService; private final INetworkPolicyManager mPolicyManager; @@ -191,10 +185,12 @@ public class Tethering extends BaseNetworkObserver { private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; private final Handler mHandler; - private final RemoteCallbackList mTetheringEventCallbacks = - new RemoteCallbackList<>(); private final PhoneStateListener mPhoneStateListener; + private final INetd mNetd; + private final NetdCallback mNetdCallback; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; + // All the usage of mTetherInternalCallback should run in the same thread. + private ITetherInternalCallback mTetherInternalCallback = null; private volatile TetheringConfiguration mConfig; private InterfaceSet mCurrentUpstreamIfaceSet; @@ -205,18 +201,17 @@ public class Tethering extends BaseNetworkObserver { // True iff. WiFi tethering should be started when soft AP is ready. private boolean mWifiTetherRequested; private Network mTetherUpstream; + private TetherStatesParcel mTetherStatesParcel; - public Tethering(Context context, INetworkManagementService nmService, - INetworkStatsService statsService, INetworkPolicyManager policyManager, - Looper looper, MockableSystemProperties systemProperties, - TetheringDependencies deps) { - mLog.mark("constructed"); - mContext = context; - mNMService = nmService; - mStatsService = statsService; - mPolicyManager = policyManager; - mLooper = looper; + public Tethering(TetheringDependencies deps) { + mLog.mark("Tethering.constructed"); mDeps = deps; + mContext = mDeps.getContext(); + mNMService = mDeps.getINetworkManagementService(); + mStatsService = mDeps.getINetworkStatsService(); + mPolicyManager = mDeps.getINetworkPolicyManager(); + mNetd = mDeps.getINetd(mContext); + mLooper = mDeps.getTetheringLooper(); mPublicSync = new Object(); @@ -239,7 +234,7 @@ public class Tethering extends BaseNetworkObserver { // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream // permission is changed according to entitlement check result. mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog, - TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties); + TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED); mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> { mLog.log("OBSERVED UiEnitlementFailed"); stopTethering(downstream); @@ -278,10 +273,18 @@ public class Tethering extends BaseNetworkObserver { mStateReceiver = new StateReceiver(); + mNetdCallback = new NetdCallback(); + try { + mNetd.registerUnsolicitedEventListener(mNetdCallback); + } catch (RemoteException e) { + mLog.e("Unable to register netd UnsolicitedEventListener"); + } + // Load tethering configuration. updateConfiguration(); startStateMachineUpdaters(mHandler); + startTrackDefaultNetwork(); } private void startStateMachineUpdaters(Handler handler) { @@ -318,6 +321,7 @@ public class Tethering extends BaseNetworkObserver { private void updateConfiguration() { mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId); mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired); + reportConfigurationChanged(mConfig.toStableParcelable()); } private void maybeDunSettingChanged() { @@ -327,10 +331,31 @@ public class Tethering extends BaseNetworkObserver { updateConfiguration(); } - @Override - public void interfaceStatusChanged(String iface, boolean up) { + private class NetdCallback extends BaseNetdUnsolicitedEventListener { + @Override + public void onInterfaceChanged(String ifName, boolean up) { + mHandler.post(() -> interfaceStatusChanged(ifName, up)); + } + + @Override + public void onInterfaceLinkStateChanged(String ifName, boolean up) { + mHandler.post(() -> interfaceLinkStateChanged(ifName, up)); + } + + @Override + public void onInterfaceAdded(String ifName) { + mHandler.post(() -> interfaceAdded(ifName)); + } + + @Override + public void onInterfaceRemoved(String ifName) { + mHandler.post(() -> interfaceRemoved(ifName)); + } + } + + void interfaceStatusChanged(String iface, boolean up) { // Never called directly: only called from interfaceLinkStateChanged. - // See NetlinkHandler.cpp:71. + // See NetlinkHandler.cpp: notifyInterfaceChanged. if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up); synchronized (mPublicSync) { if (up) { @@ -349,8 +374,7 @@ public class Tethering extends BaseNetworkObserver { } } - @Override - public void interfaceLinkStateChanged(String iface, boolean up) { + void interfaceLinkStateChanged(String iface, boolean up) { interfaceStatusChanged(iface, up); } @@ -369,28 +393,27 @@ public class Tethering extends BaseNetworkObserver { return TETHERING_INVALID; } - @Override - public void interfaceAdded(String iface) { + void interfaceAdded(String iface) { if (VDBG) Log.d(TAG, "interfaceAdded " + iface); synchronized (mPublicSync) { maybeTrackNewInterfaceLocked(iface); } } - @Override - public void interfaceRemoved(String iface) { + + void interfaceRemoved(String iface) { if (VDBG) Log.d(TAG, "interfaceRemoved " + iface); synchronized (mPublicSync) { stopTrackingInterfaceLocked(iface); } } - public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { + void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi); enableTetheringInternal(type, true /* enabled */, receiver); } - public void stopTethering(int type) { + void stopTethering(int type) { enableTetheringInternal(type, false /* disabled */, null); mEntitlementMgr.stopProvisioningIfNeeded(type); } @@ -434,8 +457,8 @@ public class Tethering extends BaseNetworkObserver { mLog.e("setWifiTethering: failed to get WifiManager!"); return TETHER_ERROR_SERVICE_UNAVAIL; } - if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) || - (!enable && mgr.stopSoftAp())) { + if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) + || (!enable && mgr.stopSoftAp())) { mWifiTetherRequested = enable; return TETHER_ERROR_NO_ERROR; } @@ -450,8 +473,8 @@ public class Tethering extends BaseNetworkObserver { private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null || !adapter.isEnabled()) { - Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + - (adapter == null)); + Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + + (adapter == null)); sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL); return; } @@ -487,7 +510,7 @@ public class Tethering extends BaseNetworkObserver { }, BluetoothProfile.PAN); } - public int tether(String iface) { + int tether(String iface) { return tether(iface, IpServer.STATE_TETHERED); } @@ -515,7 +538,7 @@ public class Tethering extends BaseNetworkObserver { } } - public int untether(String iface) { + int untether(String iface) { if (DBG) Log.d(TAG, "Untethering " + iface); synchronized (mPublicSync) { TetherState tetherState = mTetherStates.get(iface); @@ -532,19 +555,19 @@ public class Tethering extends BaseNetworkObserver { } } - public void untetherAll() { + void untetherAll() { stopTethering(TETHERING_WIFI); stopTethering(TETHERING_WIFI_P2P); stopTethering(TETHERING_USB); stopTethering(TETHERING_BLUETOOTH); } - public int getLastTetherError(String iface) { + int getLastTetherError(String iface) { synchronized (mPublicSync) { TetherState tetherState = mTetherStates.get(iface); if (tetherState == null) { - Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + - ", ignoring"); + Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + + ", ignoring"); return TETHER_ERROR_UNKNOWN_IFACE; } return tetherState.lastError; @@ -559,12 +582,14 @@ public class Tethering extends BaseNetworkObserver { final ArrayList tetherList = new ArrayList<>(); final ArrayList localOnlyList = new ArrayList<>(); final ArrayList erroredList = new ArrayList<>(); + final ArrayList lastErrorList = new ArrayList<>(); boolean wifiTethered = false; boolean usbTethered = false; boolean bluetoothTethered = false; final TetheringConfiguration cfg = mConfig; + final TetherStatesParcel mTetherStatesParcel = new TetherStatesParcel(); synchronized (mPublicSync) { for (int i = 0; i < mTetherStates.size(); i++) { @@ -572,6 +597,7 @@ public class Tethering extends BaseNetworkObserver { String iface = mTetherStates.keyAt(i); if (tetherState.lastError != TETHER_ERROR_NO_ERROR) { erroredList.add(iface); + lastErrorList.add(tetherState.lastError); } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) { availableList.add(iface); } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) { @@ -588,9 +614,21 @@ public class Tethering extends BaseNetworkObserver { } } } + + mTetherStatesParcel.availableList = availableList.toArray(new String[0]); + mTetherStatesParcel.tetheredList = tetherList.toArray(new String[0]); + mTetherStatesParcel.localOnlyList = localOnlyList.toArray(new String[0]); + mTetherStatesParcel.erroredIfaceList = erroredList.toArray(new String[0]); + mTetherStatesParcel.lastErrorList = new int[lastErrorList.size()]; + Iterator iterator = lastErrorList.iterator(); + for (int i = 0; i < lastErrorList.size(); i++) { + mTetherStatesParcel.lastErrorList[i] = iterator.next().intValue(); + } + reportTetherStateChanged(mTetherStatesParcel); + final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED); - bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | - Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING + | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList); bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList); bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList); @@ -638,16 +676,16 @@ public class Tethering extends BaseNetworkObserver { } int icon = 0; switch(id) { - case SystemMessage.NOTE_TETHER_USB: - icon = com.android.internal.R.drawable.stat_sys_tether_usb; - break; - case SystemMessage.NOTE_TETHER_BLUETOOTH: - icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth; - break; - case SystemMessage.NOTE_TETHER_GENERAL: - default: - icon = com.android.internal.R.drawable.stat_sys_tether_general; - break; + case SystemMessage.NOTE_TETHER_USB: + icon = com.android.internal.R.drawable.stat_sys_tether_usb; + break; + case SystemMessage.NOTE_TETHER_BLUETOOTH: + icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth; + break; + case SystemMessage.NOTE_TETHER_GENERAL: + default: + icon = com.android.internal.R.drawable.stat_sys_tether_general; + break; } if (mLastNotificationId != 0) { @@ -701,7 +739,7 @@ public class Tethering extends BaseNetworkObserver { @VisibleForTesting protected void clearTetheredNotification() { NotificationManager notificationManager = - (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager != null && mLastNotificationId != 0) { notificationManager.cancelAsUser(null, mLastNotificationId, UserHandle.ALL); @@ -732,8 +770,8 @@ public class Tethering extends BaseNetworkObserver { private void handleConnectivityAction(Intent intent) { final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO); - if (networkInfo == null || - networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) { + if (networkInfo == null + || networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) { return; } @@ -888,8 +926,8 @@ public class Tethering extends BaseNetworkObserver { } } - mLog.log("Error disabling Wi-Fi IP serving; " + - (TextUtils.isEmpty(ifname) ? "no interface name specified" + mLog.log("Error disabling Wi-Fi IP serving; " + + (TextUtils.isEmpty(ifname) ? "no interface name specified" : "specified interface: " + ifname)); } @@ -928,8 +966,8 @@ public class Tethering extends BaseNetworkObserver { changeInterfaceState(ifname, ipServingMode); } else { mLog.e(String.format( - "Cannot enable IP serving in mode %s on missing interface name", - ipServingMode)); + "Cannot enable IP serving in mode %s on missing interface name", + ipServingMode)); } } @@ -989,11 +1027,11 @@ public class Tethering extends BaseNetworkObserver { } } - public TetheringConfiguration getTetheringConfiguration() { + TetheringConfiguration getTetheringConfiguration() { return mConfig; } - public boolean hasTetherableConfiguration() { + boolean hasTetherableConfiguration() { final TetheringConfiguration cfg = mConfig; final boolean hasDownstreamConfiguration = (cfg.tetherableUsbRegexs.length != 0) @@ -1007,19 +1045,19 @@ public class Tethering extends BaseNetworkObserver { // TODO - update callers to use getTetheringConfiguration(), // which has only final members. - public String[] getTetherableUsbRegexs() { + String[] getTetherableUsbRegexs() { return copy(mConfig.tetherableUsbRegexs); } - public String[] getTetherableWifiRegexs() { + String[] getTetherableWifiRegexs() { return copy(mConfig.tetherableWifiRegexs); } - public String[] getTetherableBluetoothRegexs() { + String[] getTetherableBluetoothRegexs() { return copy(mConfig.tetherableBluetoothRegexs); } - public int setUsbTethering(boolean enable) { + int setUsbTethering(boolean enable) { if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")"); UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); if (usbManager == null) { @@ -1035,7 +1073,7 @@ public class Tethering extends BaseNetworkObserver { } // TODO review API - figure out how to delete these entirely. - public String[] getTetheredIfaces() { + String[] getTetheredIfaces() { ArrayList list = new ArrayList(); synchronized (mPublicSync) { for (int i = 0; i < mTetherStates.size(); i++) { @@ -1048,7 +1086,7 @@ public class Tethering extends BaseNetworkObserver { return list.toArray(new String[list.size()]); } - public String[] getTetherableIfaces() { + String[] getTetherableIfaces() { ArrayList list = new ArrayList(); synchronized (mPublicSync) { for (int i = 0; i < mTetherStates.size(); i++) { @@ -1061,13 +1099,13 @@ public class Tethering extends BaseNetworkObserver { return list.toArray(new String[list.size()]); } - public String[] getTetheredDhcpRanges() { + String[] getTetheredDhcpRanges() { // TODO: this is only valid for the old DHCP server. Latest search suggests it is only used // by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers. return mConfig.legacyDhcpRanges; } - public String[] getErroredIfaces() { + String[] getErroredIfaces() { ArrayList list = new ArrayList(); synchronized (mPublicSync) { for (int i = 0; i < mTetherStates.size(); i++) { @@ -1518,8 +1556,8 @@ public class Tethering extends BaseNetworkObserver { } if (DBG) { - Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() + - " live requests:"); + Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() + + " live requests:"); for (IpServer o : mNotifyList) { Log.d(TAG, " " + o); } @@ -1588,7 +1626,7 @@ public class Tethering extends BaseNetworkObserver { transitionTo(mInitialState); break; default: - retValue = false; + retValue = false; } return retValue; } @@ -1625,7 +1663,7 @@ public class Tethering extends BaseNetworkObserver { notify(IpServer.CMD_START_TETHERING_ERROR); try { mNMService.setIpForwardingEnabled(false); - } catch (Exception e) {} + } catch (Exception e) { } } } @@ -1636,7 +1674,7 @@ public class Tethering extends BaseNetworkObserver { notify(IpServer.CMD_STOP_TETHERING_ERROR); try { mNMService.setIpForwardingEnabled(false); - } catch (Exception e) {} + } catch (Exception e) { } } } @@ -1647,10 +1685,10 @@ public class Tethering extends BaseNetworkObserver { notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR); try { mNMService.stopTethering(); - } catch (Exception e) {} + } catch (Exception e) { } try { mNMService.setIpForwardingEnabled(false); - } catch (Exception e) {} + } catch (Exception e) { } } } @@ -1731,55 +1769,66 @@ public class Tethering extends BaseNetworkObserver { } } - public void systemReady() { + private void startTrackDefaultNetwork() { mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(), mEntitlementMgr); } /** Get the latest value of the tethering entitlement check. */ - public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver, + void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi) { if (receiver != null) { - mEntitlementMgr.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + mEntitlementMgr.requestLatestTetheringEntitlementResult(type, receiver, + showEntitlementUi); } } /** Register tethering event callback */ - public void registerTetheringEventCallback(ITetheringEventCallback callback) { + void registerTetherInternalCallback(ITetherInternalCallback callback) { mHandler.post(() -> { + mTetherInternalCallback = callback; try { - callback.onUpstreamChanged(mTetherUpstream); + mTetherInternalCallback.onCallbackCreated(mTetherUpstream, + mConfig.toStableParcelable(), mTetherStatesParcel); } catch (RemoteException e) { // Not really very much to do here. } - mTetheringEventCallbacks.register(callback); - }); - } - - /** Unregister tethering event callback */ - public void unregisterTetheringEventCallback(ITetheringEventCallback callback) { - mHandler.post(() -> { - mTetheringEventCallbacks.unregister(callback); }); } private void reportUpstreamChanged(Network network) { - final int length = mTetheringEventCallbacks.beginBroadcast(); + // Don't need to synchronized mTetherInternalCallback because all the usage of this variable + // should run at the same thread. + if (mTetherInternalCallback == null) return; + try { - for (int i = 0; i < length; i++) { - try { - mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network); - } catch (RemoteException e) { - // Not really very much to do here. - } - } - } finally { - mTetheringEventCallbacks.finishBroadcast(); + mTetherInternalCallback.onUpstreamChanged(network); + } catch (RemoteException e) { + // Not really very much to do here. } } - @Override - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + private void reportConfigurationChanged(TetheringConfigurationParcel config) { + if (mTetherInternalCallback == null) return; + + try { + mTetherInternalCallback.onConfigurationChanged(config); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + + private void reportTetherStateChanged(TetherStatesParcel states) { + if (mTetherInternalCallback == null) return; + + try { + mTetherInternalCallback.onTetherStatesChanged(states); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + + void dump(FileDescriptor fd, PrintWriter writer, String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -1838,7 +1887,7 @@ public class Tethering extends BaseNetworkObserver { pw.println("Log:"); pw.increaseIndent(); - if (argsContain(args, SHORT_ARG)) { + if (argsContain(args, "--short")) { pw.println(""); } else { mLog.dump(fd, pw, args); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index ca9b1681bacca..0ab4d634e84da 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -38,6 +38,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.TetheringConfigurationParcel; import android.net.util.SharedLog; import android.provider.Settings; import android.telephony.SubscriptionManager; @@ -384,4 +385,32 @@ public class TetheringConfiguration { } return false; } + + /** + * Convert this TetheringConfiguration to a TetheringConfigurationParcel. + */ + public TetheringConfigurationParcel toStableParcelable() { + final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel(); + parcel.subId = subId; + parcel.tetherableUsbRegexs = tetherableUsbRegexs; + parcel.tetherableWifiRegexs = tetherableWifiRegexs; + parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs; + parcel.isDunRequired = isDunRequired; + parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically; + + int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()]; + int index = 0; + for (Integer type : preferredUpstreamIfaceTypes) { + preferredTypes[index++] = type; + } + parcel.preferredUpstreamIfaceTypes = preferredTypes; + + parcel.legacyDhcpRanges = legacyDhcpRanges; + parcel.defaultIPv4DNS = defaultIPv4DNS; + parcel.enableLegacyDhcpServer = enableLegacyDhcpServer; + parcel.provisioningApp = provisioningApp; + parcel.provisioningAppNoUi = provisioningAppNoUi; + parcel.provisioningCheckPeriod = provisioningCheckPeriod; + return parcel; + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java similarity index 59% rename from services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java rename to packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java index 4ad7ac4bead06..0ba84127d8da3 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -17,13 +17,19 @@ package com.android.server.connectivity.tethering; import android.content.Context; +import android.net.INetd; +import android.net.INetworkPolicyManager; +import android.net.INetworkStatsService; import android.net.NetworkRequest; import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.ServiceManager; import com.android.internal.util.StateMachine; -import com.android.server.connectivity.MockableSystemProperties; import java.util.ArrayList; @@ -82,8 +88,8 @@ public class TetheringDependencies { * Get a reference to the EntitlementManager to be used by tethering. */ public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, - SharedLog log, int what, MockableSystemProperties systemProperties) { - return new EntitlementManager(ctx, target, log, what, systemProperties); + SharedLog log, int what) { + return new EntitlementManager(ctx, target, log, what); } /** @@ -93,4 +99,53 @@ public class TetheringDependencies { int subId) { return new TetheringConfiguration(ctx, log, subId); } + + /** + * Get a reference to INetworkManagementService to registerTetheringStatsProvider from + * OffloadController. Note: This should be removed soon by Usage refactor work in R + * development cycle. + */ + public INetworkManagementService getINetworkManagementService() { + return INetworkManagementService.Stub.asInterface( + ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + } + + /** + * Get a reference to INetworkStatsService to force update tethering usage. + * Note: This should be removed in R development cycle. + */ + public INetworkStatsService getINetworkStatsService() { + return INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + } + + /** + * Get a reference to INetworkPolicyManager to be used by tethering. + */ + public INetworkPolicyManager getINetworkPolicyManager() { + return INetworkPolicyManager.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); + } + + /** + * Get a reference to INetd to be used by tethering. + */ + public INetd getINetd(Context context) { + return INetd.Stub.asInterface( + (IBinder) context.getSystemService(Context.NETD_SERVICE)); + } + + /** + * Get tethering thread looper. + */ + public Looper getTetheringLooper() { + return null; + } + + /** + * Get Context of TetheringSerice. + */ + public Context getContext() { + return null; + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java similarity index 100% rename from services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java rename to packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java new file mode 100644 index 0000000000000..456f2f7f27f59 --- /dev/null +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2019 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.app.Service; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.ITetherInternalCallback; +import android.net.ITetheringConnector; +import android.net.NetworkRequest; +import android.net.util.SharedLog; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.ResultReceiver; +import android.os.SystemProperties; +import android.provider.Settings; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Android service used to manage tethering. + * + *

The service returns a binder for the system server to communicate with the tethering. + */ +public class TetheringService extends Service { + private static final String TAG = TetheringService.class.getSimpleName(); + + private final SharedLog mLog = new SharedLog(TAG); + private TetheringConnector mConnector; + private Context mContext; + private TetheringDependencies mDeps; + private Tethering mTethering; + + @Override + public void onCreate() { + mLog.mark("onCreate"); + mDeps = getTetheringDependencies(); + mContext = mDeps.getContext(); + mTethering = makeTethering(mDeps); + } + + /** + * Make a reference to Tethering object. + */ + @VisibleForTesting + public Tethering makeTethering(TetheringDependencies deps) { + return new Tethering(deps); + } + + /** + * Create a binder connector for the system server to communicate with the tethering. + */ + private synchronized IBinder makeConnector() { + if (mConnector == null) { + mConnector = new TetheringConnector(mTethering); + } + return mConnector; + } + + @NonNull + @Override + public IBinder onBind(Intent intent) { + mLog.mark("onBind"); + return makeConnector(); + } + + private static class TetheringConnector extends ITetheringConnector.Stub { + private final Tethering mService; + + TetheringConnector(Tethering tether) { + mService = tether; + } + + @Override + public void tether(String iface) { + mService.tether(iface); + } + + @Override + public void untether(String iface) { + mService.untether(iface); + } + + @Override + public void setUsbTethering(boolean enable) { + mService.setUsbTethering(enable); + } + + @Override + public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { + mService.startTethering(type, receiver, showProvisioningUi); + } + + @Override + public void stopTethering(int type) { + mService.stopTethering(type); + } + + @Override + public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, + boolean showEntitlementUi) { + mService.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + } + + @Override + public void registerTetherInternalCallback(ITetherInternalCallback callback) { + mService.registerTetherInternalCallback(callback); + } + } + + @Override + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, + @Nullable String[] args) { + mTethering.dump(fd, writer, args); + } + + /** + * An injection method for testing. + */ + @VisibleForTesting + public TetheringDependencies getTetheringDependencies() { + if (mDeps == null) { + mDeps = new TetheringDependencies() { + @Override + public NetworkRequest getDefaultNetworkRequest() { + ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + return cm.getDefaultRequest(); + } + + @Override + public Looper getTetheringLooper() { + final HandlerThread tetherThread = new HandlerThread("android.tethering"); + tetherThread.start(); + return tetherThread.getLooper(); + } + + @Override + public boolean isTetheringSupported() { + int defaultVal = + SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; + return tetherSupported; + } + + @Override + public Context getContext() { + return TetheringService.this; + } + }; + } + + return mDeps; + } +} diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 363be18a73bcd..5b018df21aaff 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -18,7 +18,6 @@ android_test { name: "TetheringTests", certificate: "platform", srcs: [ - ":servicescore-tethering-src", "src/**/*.java", ], test_suites: ["device-tests"], @@ -41,17 +40,3 @@ android_test { "libstaticjvmtiagent", ], } - -// This group would be removed when tethering migration is done. -filegroup { - name: "tethering-tests-src", - srcs: [ - "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java", - "src/com/android/server/connectivity/tethering/OffloadControllerTest.java", - "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java", - "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java", - "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java", - "src/android/net/ip/IpServerTest.java", - "src/android/net/util/InterfaceSetTest.java", - ], -} diff --git a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java similarity index 97% rename from tests/net/java/android/net/util/VersionedBroadcastListenerTest.java rename to packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java index 0d27d5bf0a111..5a9b6e380ea9a 100644 --- a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java @@ -51,7 +51,9 @@ public class VersionedBroadcastListenerTest { private VersionedBroadcastListener mListener; private int mCallbackCount; - private void doCallback() { mCallbackCount++; } + private void doCallback() { + mCallbackCount++; + } private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { @@ -96,7 +98,7 @@ public class VersionedBroadcastListenerTest { mListener.startListening(); for (int i = 0; i < 5; i++) { sendBroadcast(); - assertEquals(i+1, mCallbackCount); + assertEquals(i + 1, mCallbackCount); } mListener.stopListening(); } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 5217e26a40efb..99cf9e90d9121 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -24,6 +24,9 @@ import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -44,6 +47,7 @@ import android.os.Bundle; import android.os.Message; import android.os.PersistableBundle; import android.os.ResultReceiver; +import android.os.SystemProperties; import android.os.test.TestLooper; import android.provider.Settings; import android.telephony.CarrierConfigManager; @@ -57,7 +61,6 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.server.connectivity.MockableSystemProperties; import org.junit.After; import org.junit.Before; @@ -65,6 +68,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; @@ -80,7 +85,6 @@ public final class EntitlementManagerTest { @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private Context mContext; - @Mock private MockableSystemProperties mSystemProperties; @Mock private Resources mResources; @Mock private SharedLog mLog; @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener; @@ -95,6 +99,7 @@ public final class EntitlementManagerTest { private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; private TetheringConfiguration mConfig; + private MockitoSession mMockingSession; private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { @@ -118,8 +123,8 @@ public final class EntitlementManagerTest { public int silentProvisionCount = 0; public WrappedEntitlementManager(Context ctx, StateMachine target, - SharedLog log, int what, MockableSystemProperties systemProperties) { - super(ctx, target, log, what, systemProperties); + SharedLog log, int what) { + super(ctx, target, log, what); } public void reset() { @@ -144,6 +149,15 @@ public final class EntitlementManagerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mMockingSession = mockitoSession() + .initMocks(this) + .spyStatic(SystemProperties.class) + .strictness(Strictness.WARN) + .startMocking(); + // Don't disable tethering provisioning unless requested. + doReturn(false).when( + () -> SystemProperties.getBoolean( + eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); @@ -161,8 +175,7 @@ public final class EntitlementManagerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); - mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE, - mSystemProperties); + mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); mEnMgr.setTetheringConfigurationFetcher(() -> { @@ -176,6 +189,7 @@ public final class EntitlementManagerTest { mSM.quit(); mSM = null; } + mMockingSession.finishMocking(); } private void setupForRequiredProvisioning() { @@ -184,9 +198,6 @@ public final class EntitlementManagerTest { .thenReturn(PROVISIONING_APP_NAME); when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui)) .thenReturn(PROVISIONING_NO_UI_APP_NAME); - // Don't disable tethering provisioning unless requested. - when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), - anyBoolean())).thenReturn(false); // Act like the CarrierConfigManager is present and ready unless told otherwise. when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(mCarrierConfigManager); @@ -244,7 +255,7 @@ public final class EntitlementManagerTest { } @Test - public void testGetLastEntitlementCacheValue() throws Exception { + public void testRequestLastEntitlementCacheValue() throws Exception { final CountDownLatch mCallbacklatch = new CountDownLatch(1); // 1. Entitlement check is not required. mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; @@ -255,7 +266,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); @@ -270,7 +281,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); @@ -284,7 +295,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); @@ -298,7 +309,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); @@ -312,7 +323,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); @@ -326,7 +337,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); @@ -339,7 +350,7 @@ public final class EntitlementManagerTest { mCallbacklatch.countDown(); } }; - mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false); + mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_USB, receiver, false); mLooper.dispatchAll(); callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java similarity index 86% rename from tests/net/java/com/android/server/connectivity/TetheringTest.java rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 9e5717b4bd642..4f6f61bf95d69 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity; +package com.android.server.connectivity.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -39,7 +39,9 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; @@ -70,7 +72,7 @@ import android.hardware.usb.UsbManager; import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.ITetheringEventCallback; +import android.net.ITetherInternalCallback; import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; @@ -82,6 +84,8 @@ import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; +import android.net.TetherStatesParcel; +import android.net.TetheringConfigurationParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; @@ -98,6 +102,7 @@ import android.net.wifi.p2p.WifiP2pManager; import android.os.Bundle; import android.os.Handler; import android.os.INetworkManagementService; +import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; @@ -109,6 +114,7 @@ import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -116,11 +122,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; -import com.android.server.connectivity.tethering.OffloadHardwareInterface; -import com.android.server.connectivity.tethering.TetheringConfiguration; -import com.android.server.connectivity.tethering.TetheringDependencies; -import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; import org.junit.After; import org.junit.Before; @@ -154,7 +155,6 @@ public class TetheringTest { @Mock private INetworkManagementService mNMService; @Mock private INetworkStatsService mStatsService; @Mock private INetworkPolicyManager mPolicyManager; - @Mock private MockableSystemProperties mSystemProperties; @Mock private OffloadHardwareInterface mOffloadHardwareInterface; @Mock private Resources mResources; @Mock private TelephonyManager mTelephonyManager; @@ -184,22 +184,30 @@ public class TetheringTest { private Tethering mTethering; private PhoneStateListener mPhoneStateListener; - private class MockContext extends BroadcastInterceptingContext { - MockContext(Context base) { + private class TestContext extends BroadcastInterceptingContext { + TestContext(Context base) { super(base); } @Override - public ApplicationInfo getApplicationInfo() { return mApplicationInfo; } + public ApplicationInfo getApplicationInfo() { + return mApplicationInfo; + } @Override - public ContentResolver getContentResolver() { return mContentResolver; } + public ContentResolver getContentResolver() { + return mContentResolver; + } @Override - public String getPackageName() { return "TetheringTest"; } + public String getPackageName() { + return "TetheringTest"; + } @Override - public Resources getResources() { return mResources; } + public Resources getResources() { + return mResources; + } @Override public Object getSystemService(String name) { @@ -266,14 +274,14 @@ public class TetheringTest { } public class MockTetheringDependencies extends TetheringDependencies { - StateMachine upstreamNetworkMonitorMasterSM; - ArrayList ipv6CoordinatorNotifyList; - int isTetheringSupportedCalls; + StateMachine mUpstreamNetworkMonitorMasterSM; + ArrayList mIpv6CoordinatorNotifyList; + int mIsTetheringSupportedCalls; public void reset() { - upstreamNetworkMonitorMasterSM = null; - ipv6CoordinatorNotifyList = null; - isTetheringSupportedCalls = 0; + mUpstreamNetworkMonitorMasterSM = null; + mIpv6CoordinatorNotifyList = null; + mIsTetheringSupportedCalls = 0; } @Override @@ -284,14 +292,14 @@ public class TetheringTest { @Override public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target, SharedLog log, int what) { - upstreamNetworkMonitorMasterSM = target; + mUpstreamNetworkMonitorMasterSM = target; return mUpstreamNetworkMonitor; } @Override public IPv6TetheringCoordinator getIPv6TetheringCoordinator( ArrayList notifyList, SharedLog log) { - ipv6CoordinatorNotifyList = notifyList; + mIpv6CoordinatorNotifyList = notifyList; return mIPv6TetheringCoordinator; } @@ -302,7 +310,7 @@ public class TetheringTest { @Override public boolean isTetheringSupported() { - isTetheringSupportedCalls++; + mIsTetheringSupportedCalls++; return true; } @@ -311,6 +319,36 @@ public class TetheringTest { int subId) { return new MockTetheringConfiguration(ctx, log, subId); } + + @Override + public INetworkManagementService getINetworkManagementService() { + return mNMService; + } + + @Override + public INetworkStatsService getINetworkStatsService() { + return mStatsService; + } + + @Override + public INetworkPolicyManager getINetworkPolicyManager() { + return mPolicyManager; + } + + @Override + public INetd getINetd(Context context) { + return mNetd; + } + + @Override + public Looper getTetheringLooper() { + return mLooper.getLooper(); + } + + @Override + public Context getContext() { + return mServiceContext; + } } private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, @@ -345,7 +383,7 @@ public class TetheringTest { final NetworkCapabilities capabilities = new NetworkCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);; + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); return new NetworkState(info, prop, capabilities, new Network(100), null, "netid"); } @@ -390,7 +428,7 @@ public class TetheringTest { when(mRouterAdvertisementDaemon.start()) .thenReturn(true); - mServiceContext = new MockContext(mContext); + mServiceContext = new TestContext(mContext); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); @@ -403,9 +441,9 @@ public class TetheringTest { }; mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); - mTetheringDependencies.reset(); mTethering = makeTethering(); verify(mNMService).registerTetheringStatsProvider(any(), anyString()); + verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor phoneListenerCaptor = ArgumentCaptor.forClass(PhoneStateListener.class); verify(mTelephonyManager).listen(phoneListenerCaptor.capture(), @@ -414,9 +452,8 @@ public class TetheringTest { } private Tethering makeTethering() { - return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager, - mLooper.getLooper(), mSystemProperties, - mTetheringDependencies); + mTetheringDependencies.reset(); + return new Tethering(mTetheringDependencies); } @After @@ -507,7 +544,7 @@ public class TetheringTest { // it creates a IpServer and sends out a broadcast indicating that the // interface is "available". if (emulateInterfaceStatusChanged) { - assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); @@ -584,7 +621,7 @@ public class TetheringTest { verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); // Emulate externally-visible WifiManager effects, when hotspot mode // is being torn down. @@ -617,8 +654,7 @@ public class TetheringTest { argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)), eq(IpServer.STATE_TETHERED)); - for (IpServer ipSrv : - mTetheringDependencies.ipv6CoordinatorNotifyList) { + for (IpServer ipSrv : mTetheringDependencies.mIpv6CoordinatorNotifyList) { NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false); ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, upstreamState.linkProperties.isIpv6Provisioned() @@ -650,7 +686,7 @@ public class TetheringTest { @Test public void workingMobileUsbTethering_IPv4LegacyDhcp() { Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); - mTethering = makeTethering(); + sendConfigurationChanged(); final NetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); sendIPv6TetherUpdates(upstreamState); @@ -719,7 +755,7 @@ public class TetheringTest { .thenReturn(upstreamState); // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES. - mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage( + mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage( Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0, @@ -784,7 +820,7 @@ public class TetheringTest { sendWifiApStateChanged(WIFI_AP_STATE_ENABLED); mLooper.dispatchAll(); - assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); @@ -828,7 +864,7 @@ public class TetheringTest { verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest(); // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); ///// // We do not currently emulate any upstream being found. @@ -901,7 +937,7 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); // There are 3 state change event: // AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE. - assertEquals(3, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); // This is called, but will throw. verify(mNMService, times(1)).setIpForwardingEnabled(true); @@ -919,8 +955,8 @@ public class TetheringTest { } private void userRestrictionsListenerBehaviour( - boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, - int expectedInteractionsWithShowNotification) throws Exception { + boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, + int expectedInteractionsWithShowNotification) throws Exception { final int userId = 0; final Bundle currRestrictions = new Bundle(); final Bundle newRestrictions = new Bundle(); @@ -1001,17 +1037,49 @@ public class TetheringTest { expectedInteractionsWithShowNotification); } - private class TestTetheringEventCallback extends ITetheringEventCallback.Stub { + private class TestTetherInternalCallback extends ITetherInternalCallback.Stub { private final ArrayList mActualUpstreams = new ArrayList<>(); + private final ArrayList mTetheringConfigs = + new ArrayList<>(); + private final ArrayList mTetherStates = new ArrayList<>(); + // This function will remove the recorded callbacks, so it must be called once for + // each callback. If this is called after multiple callback, the order matters. + // onCallbackCreated counts as the first call to expectUpstreamChanged with + // @see onCallbackCreated. public void expectUpstreamChanged(Network... networks) { + if (networks == null) { + assertNoUpstreamChangeCallback(); + return; + } + final ArrayList expectedUpstreams = new ArrayList(Arrays.asList(networks)); for (Network upstream : expectedUpstreams) { // throws OOB if no expectations assertEquals(mActualUpstreams.remove(0), upstream); } - assertNoCallback(); + assertNoUpstreamChangeCallback(); + } + + // This function will remove the recorded callbacks, so it must be called once + // for each callback. If this is called after multiple callback, the order matters. + // onCallbackCreated counts as the first call to onConfigurationChanged with + // @see onCallbackCreated. + public void expectConfigurationChanged(TetheringConfigurationParcel... tetherConfigs) { + final ArrayList expectedTetherConfig = + new ArrayList(Arrays.asList(tetherConfigs)); + for (TetheringConfigurationParcel config : expectedTetherConfig) { + // throws OOB if no expectations + final TetheringConfigurationParcel actualConfig = mTetheringConfigs.remove(0); + assertTetherConfigParcelEqual(actualConfig, config); + } + assertNoConfigChangeCallback(); + } + + public TetherStatesParcel pollTetherStatesChanged() { + assertStateChangeCallback(); + return mTetherStates.remove(0); } @Override @@ -1019,48 +1087,93 @@ public class TetheringTest { mActualUpstreams.add(network); } - public void assertNoCallback() { + @Override + public void onConfigurationChanged(TetheringConfigurationParcel config) { + mTetheringConfigs.add(config); + } + + @Override + public void onTetherStatesChanged(TetherStatesParcel states) { + mTetherStates.add(states); + } + + @Override + public void onCallbackCreated(Network network, TetheringConfigurationParcel config, + TetherStatesParcel states) { + mActualUpstreams.add(network); + mTetheringConfigs.add(config); + mTetherStates.add(states); + } + + public void assertNoUpstreamChangeCallback() { assertTrue(mActualUpstreams.isEmpty()); } + + public void assertNoConfigChangeCallback() { + assertTrue(mTetheringConfigs.isEmpty()); + } + + public void assertStateChangeCallback() { + assertFalse(mTetherStates.isEmpty()); + } + + private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual, + @NonNull TetheringConfigurationParcel expect) { + assertEquals(actual.subId, expect.subId); + assertArrayEquals(actual.tetherableUsbRegexs, expect.tetherableUsbRegexs); + assertArrayEquals(actual.tetherableWifiRegexs, expect.tetherableWifiRegexs); + assertArrayEquals(actual.tetherableBluetoothRegexs, expect.tetherableBluetoothRegexs); + assertEquals(actual.isDunRequired, expect.isDunRequired); + assertEquals(actual.chooseUpstreamAutomatically, expect.chooseUpstreamAutomatically); + assertArrayEquals(actual.preferredUpstreamIfaceTypes, + expect.preferredUpstreamIfaceTypes); + assertArrayEquals(actual.legacyDhcpRanges, expect.legacyDhcpRanges); + assertArrayEquals(actual.defaultIPv4DNS, expect.defaultIPv4DNS); + assertEquals(actual.enableLegacyDhcpServer, expect.enableLegacyDhcpServer); + assertArrayEquals(actual.provisioningApp, expect.provisioningApp); + assertEquals(actual.provisioningAppNoUi, expect.provisioningAppNoUi); + assertEquals(actual.provisioningCheckPeriod, expect.provisioningCheckPeriod); + } } @Test - public void testRegisterTetheringEventCallback() throws Exception { - TestTetheringEventCallback callback1 = new TestTetheringEventCallback(); - TestTetheringEventCallback callback2 = new TestTetheringEventCallback(); + public void testRegisterTetherInternalCallback() throws Exception { + TestTetherInternalCallback callback = new TestTetherInternalCallback(); - // 1. Register one callback and run usb tethering. - mTethering.registerTetheringEventCallback(callback1); + // 1. Register one callback before running any tethering. + mTethering.registerTetherInternalCallback(callback); mLooper.dispatchAll(); - callback1.expectUpstreamChanged(new Network[] {null}); + callback.expectUpstreamChanged(new Network[] {null}); + callback.expectConfigurationChanged( + mTethering.getTetheringConfiguration().toStableParcelable()); + TetherStatesParcel tetherState = callback.pollTetherStatesChanged(); + assertEquals(tetherState, null); + // 2. Enable wifi tethering NetworkState upstreamState = buildMobileDualStackUpstreamState(); - runUsbTethering(upstreamState); - callback1.expectUpstreamChanged(upstreamState.network); - // 2. Register second callback. - mTethering.registerTetheringEventCallback(callback2); - mLooper.dispatchAll(); - callback2.expectUpstreamChanged(upstreamState.network); - // 3. Disable usb tethering. - mTethering.stopTethering(TETHERING_USB); - mLooper.dispatchAll(); - sendUsbBroadcast(false, false, false); - mLooper.dispatchAll(); - callback1.expectUpstreamChanged(new Network[] {null}); - callback2.expectUpstreamChanged(new Network[] {null}); - // 4. Unregister first callback and run hotspot. - mTethering.unregisterTetheringEventCallback(callback1); - mLooper.dispatchAll(); when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) .thenReturn(upstreamState); when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); - mTethering.startTethering(TETHERING_WIFI, null, false); - mLooper.dispatchAll(); mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true); + mLooper.dispatchAll(); + tetherState = callback.pollTetherStatesChanged(); + assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); + + mTethering.startTethering(TETHERING_WIFI, null, false); sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); - callback1.assertNoCallback(); - callback2.expectUpstreamChanged(upstreamState.network); + tetherState = callback.pollTetherStatesChanged(); + assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME}); + callback.expectUpstreamChanged(upstreamState.network); + + // 3. Disable wifi tethering. + mTethering.stopTethering(TETHERING_WIFI); + sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED); + mLooper.dispatchAll(); + tetherState = callback.pollTetherStatesChanged(); + assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); + mLooper.dispatchAll(); + callback.expectUpstreamChanged(new Network[] {null}); } @Test @@ -1091,7 +1204,7 @@ public class TetheringTest { verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY. - assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls); + assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls); assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME)); diff --git a/services/core/Android.bp b/services/core/Android.bp index 4900781d6df52..4e75e006e1117 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -20,7 +20,6 @@ java_library_static { ":vold_aidl", ":gsiservice_aidl", ":platform-compat-config", - ":tethering-servicescore-srcs", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", "java/com/android/server/policy/EventLogTags.logtags", @@ -81,11 +80,3 @@ prebuilt_etc { name: "gps_debug.conf", src: "java/com/android/server/location/gps_debug.conf", } - -// TODO: this should be removed after tethering migration done. -filegroup { - name: "servicescore-tethering-src", - srcs: [ - "java/com/android/server/connectivity/MockableSystemProperties.java", - ], -} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7d7104ce38c81..b2d0920e6992a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -108,6 +108,7 @@ import android.net.PrivateDnsConfigParcel; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SocketKeepalive; +import android.net.TetheringManager; import android.net.UidRange; import android.net.Uri; import android.net.VpnService; @@ -187,9 +188,7 @@ import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProxyTracker; -import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; -import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.net.BaseNetdEventCallback; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; @@ -233,7 +232,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final String DIAG_ARG = "--diag"; public static final String SHORT_ARG = "--short"; - private static final String TETHERING_ARG = "tethering"; private static final String NETWORK_ARG = "networks"; private static final String REQUEST_ARG = "requests"; @@ -280,7 +278,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private MockableSystemProperties mSystemProperties; - private Tethering mTethering; + private TetheringManager mTetheringManager; @VisibleForTesting protected final PermissionMonitor mPermissionMonitor; @@ -869,15 +867,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * @see Tethering + * Get a reference to the TetheringManager. */ - public Tethering makeTethering(@NonNull Context context, - @NonNull INetworkManagementService nms, - @NonNull INetworkStatsService statsService, - @NonNull INetworkPolicyManager policyManager, - @NonNull TetheringDependencies tetheringDeps) { - return new Tethering(context, nms, statsService, policyManager, - IoThread.get().getLooper(), getSystemProperties(), tetheringDeps); + public TetheringManager getTetheringManager() { + return TetheringManager.getInstance(); } /** @@ -1075,8 +1068,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager, - makeTetheringDependencies()); + mTetheringManager = mDeps.getTetheringManager(); mPermissionMonitor = new PermissionMonitor(mContext, mNetd); @@ -1111,7 +1103,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler); try { - mNMS.registerObserver(mTethering); mNMS.registerObserver(mDataActivityObserver); } catch (RemoteException e) { loge("Error registering observer :" + e); @@ -1145,19 +1136,6 @@ public class ConnectivityService extends IConnectivityManager.Stub registerPrivateDnsSettingsCallbacks(); } - private TetheringDependencies makeTetheringDependencies() { - return new TetheringDependencies() { - @Override - public boolean isTetheringSupported() { - return ConnectivityService.this.isTetheringSupported(); - } - @Override - public NetworkRequest getDefaultNetworkRequest() { - return mDefaultRequest; - } - }; - } - private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); @@ -1909,7 +1887,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: relocate this specific callback in Tethering. if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); - mTethering.untetherAll(); + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_USB); + mTetheringManager.stopTethering(ConnectivityManager.TETHERING_BLUETOOTH); } } }; @@ -2188,7 +2168,6 @@ public class ConnectivityService extends IConnectivityManager.Stub public void systemReady() { mProxyTracker.loadGlobalProxy(); registerNetdEventCallback(); - mTethering.systemReady(); synchronized (this) { mSystemReady = true; @@ -2402,9 +2381,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (ArrayUtils.contains(args, DIAG_ARG)) { dumpNetworkDiagnostics(pw); return; - } else if (ArrayUtils.contains(args, TETHERING_ARG)) { - mTethering.dump(fd, pw, args); - return; } else if (ArrayUtils.contains(args, NETWORK_ARG)) { dumpNetworks(pw); return; @@ -2466,10 +2442,13 @@ public class ConnectivityService extends IConnectivityManager.Stub mLegacyTypeTracker.dump(pw); pw.println(); - mTethering.dump(fd, pw, args); + mKeepaliveTracker.dump(pw); pw.println(); - mKeepaliveTracker.dump(pw); + pw.println("TetheringManager logs:"); + pw.increaseIndent(); + TetheringManager.getInstance().dump(pw); + pw.decreaseIndent(); pw.println(); dumpAvoidBadWifiSettings(pw); @@ -4001,7 +3980,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public int tether(String iface, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); if (isTetheringSupported()) { - return mTethering.tether(iface); + return mTetheringManager.tether(iface); } else { return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; } @@ -4013,7 +3992,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); if (isTetheringSupported()) { - return mTethering.untether(iface); + return mTetheringManager.untether(iface); } else { return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; } @@ -4025,7 +4004,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceTetherAccessPermission(); if (isTetheringSupported()) { - return mTethering.getLastTetherError(iface); + return mTetheringManager.getLastTetherError(iface); } else { return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; } @@ -4036,7 +4015,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public String[] getTetherableUsbRegexs() { enforceTetherAccessPermission(); if (isTetheringSupported()) { - return mTethering.getTetherableUsbRegexs(); + return mTetheringManager.getTetherableUsbRegexs(); } else { return new String[0]; } @@ -4046,7 +4025,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public String[] getTetherableWifiRegexs() { enforceTetherAccessPermission(); if (isTetheringSupported()) { - return mTethering.getTetherableWifiRegexs(); + return mTetheringManager.getTetherableWifiRegexs(); } else { return new String[0]; } @@ -4056,7 +4035,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public String[] getTetherableBluetoothRegexs() { enforceTetherAccessPermission(); if (isTetheringSupported()) { - return mTethering.getTetherableBluetoothRegexs(); + return mTetheringManager.getTetherableBluetoothRegexs(); } else { return new String[0]; } @@ -4066,7 +4045,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public int setUsbTethering(boolean enable, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); if (isTetheringSupported()) { - return mTethering.setUsbTethering(enable); + return mTetheringManager.setUsbTethering(enable); } else { return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; } @@ -4077,25 +4056,25 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String[] getTetherableIfaces() { enforceTetherAccessPermission(); - return mTethering.getTetherableIfaces(); + return mTetheringManager.getTetherableIfaces(); } @Override public String[] getTetheredIfaces() { enforceTetherAccessPermission(); - return mTethering.getTetheredIfaces(); + return mTetheringManager.getTetheredIfaces(); } @Override public String[] getTetheringErroredIfaces() { enforceTetherAccessPermission(); - return mTethering.getErroredIfaces(); + return mTetheringManager.getTetheringErroredIfaces(); } @Override public String[] getTetheredDhcpRanges() { enforceConnectivityInternalPermission(); - return mTethering.getTetheredDhcpRanges(); + return mTetheringManager.getTetheredDhcpRanges(); } @Override @@ -4123,7 +4102,8 @@ public class ConnectivityService extends IConnectivityManager.Stub Binder.restoreCallingIdentity(token); } - return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration(); + return tetherEnabledInSettings && adminUser + && mTetheringManager.hasTetherableConfiguration(); } @Override @@ -4134,13 +4114,13 @@ public class ConnectivityService extends IConnectivityManager.Stub receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null); return; } - mTethering.startTethering(type, receiver, showProvisioningUi); + mTetheringManager.startTethering(type, receiver, showProvisioningUi); } @Override public void stopTethering(int type, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTethering.stopTethering(type); + mTetheringManager.stopTethering(type); } /** @@ -4154,7 +4134,8 @@ public class ConnectivityService extends IConnectivityManager.Stub public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + mTetheringManager.requestLatestTetheringEntitlementResult( + type, receiver, showEntitlementUi); } /** Register tethering event callback. */ @@ -4162,7 +4143,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTethering.registerTetheringEventCallback(callback); + mTetheringManager.registerTetheringEventCallback(callback); } /** Unregister tethering event callback. */ @@ -4170,7 +4151,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg) { ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTethering.unregisterTetheringEventCallback(callback); + mTetheringManager.unregisterTetheringEventCallback(callback); } // Called when we lose the default network and have no replacement yet. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 08c94267e9697..e473c96980b68 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -138,7 +138,6 @@ import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.LocalServices; -import com.android.server.connectivity.Tethering; import java.io.File; import java.io.FileDescriptor; diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 7b3fbb97da56c..2b1c07ba40b1c 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -53,7 +53,6 @@ cc_library_static { "com_android_server_am_LowMemDetector.cpp", "onload.cpp", ":lib_networkStatsFactory_native", - ":tethering-jni-srcs", ], include_dirs: [ @@ -122,7 +121,6 @@ cc_defaults { "android.hardware.power@1.0", "android.hardware.power@1.1", "android.hardware.power.stats@1.0", - "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/onload.cpp b/services/core/jni/onload.cpp index efffa6ca735b8..692c9d25baa99 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -40,7 +40,6 @@ int register_android_server_vr_VrManagerService(JNIEnv* env); int register_android_server_VibratorService(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_TestNetworkService(JNIEnv* env); int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*); int register_android_server_hdmi_HdmiCecController(JNIEnv* env); @@ -88,7 +87,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_SystemServer(env); register_android_server_location_GnssLocationProvider(env); register_android_server_connectivity_Vpn(env); - register_android_server_connectivity_tethering_OffloadHardwareInterface(env); register_android_server_TestNetworkService(env); register_android_server_devicepolicy_CryptoTestHelper(env); register_android_server_ConsumerIrService(env); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 313f884c08cbe..9f09e2a5bb0a1 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -40,6 +40,7 @@ import android.database.sqlite.SQLiteGlobal; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityModuleConnector; import android.net.NetworkStackClient; +import android.net.TetheringManager; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -2184,6 +2185,15 @@ public final class SystemServer { } traceEnd(); + traceBeginAndSlog("StartTethering"); + try { + // Tethering must start after ConnectivityService and NetworkStack. + TetheringManager.getInstance().start(); + } catch (Throwable e) { + reportWtf("starting Tethering", e); + } + traceEnd(); + traceBeginAndSlog("MakeLocationServiceReady"); try { if (locationF != null) { diff --git a/services/net/Android.bp b/services/net/Android.bp index 45430eab9bf48..2dabdb7d47ded 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -2,8 +2,8 @@ java_library_static { name: "services.net", srcs: [ ":net-module-utils-srcs", - ":tethering-servicesnet-srcs", "java/**/*.java", + ":tethering-manager", ], static_libs: [ "dnsresolver_aidl_interface-V2-java", diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 10f27e243c8c9..b2f384ac8360a 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -45,7 +45,6 @@ android_test { name: "FrameworksNetTests", defaults: ["FrameworksNetTests-jni-defaults"], srcs: [ - ":tethering-tests-src", "java/**/*.java", "java/**/*.kt", ], diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 334b26d821296..25028fb3ca0ea 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -32,6 +32,7 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkRequest import android.net.TestNetworkStackClient +import android.net.TetheringManager import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder @@ -48,7 +49,6 @@ import com.android.server.connectivity.DefaultNetworkMetrics import com.android.server.connectivity.IpConnectivityMetrics import com.android.server.connectivity.MockableSystemProperties import com.android.server.connectivity.ProxyTracker -import com.android.server.connectivity.Tethering import com.android.server.net.NetworkPolicyManagerInternal import com.android.testutils.TestableNetworkCallback import org.junit.After @@ -169,8 +169,7 @@ class ConnectivityServiceIntegrationTest { val deps = spy(ConnectivityService.Dependencies()) doReturn(networkStackClient).`when`(deps).networkStack doReturn(metricsLogger).`when`(deps).metricsLogger - doReturn(mock(Tethering::class.java)).`when`(deps).makeTethering( - any(), any(), any(), any(), any()) + doReturn(mock(TetheringManager::class.java)).`when`(deps).getTetheringManager() doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any()) doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager() diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index aad2f3da40f22..7217d9b6bfa0c 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -160,6 +160,7 @@ import android.net.ProxyInfo; import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.SocketKeepalive; +import android.net.TetheringManager; import android.net.UidRange; import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; @@ -207,7 +208,6 @@ import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.ProxyTracker; -import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; @@ -1127,7 +1127,7 @@ public class ConnectivityServiceTest { doReturn(new TestNetIdManager()).when(deps).makeNetIdManager(); doReturn(mNetworkStack).when(deps).getNetworkStack(); doReturn(systemProperties).when(deps).getSystemProperties(); - doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any()); + doReturn(mock(TetheringManager.class)).when(deps).getTetheringManager(); doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); doReturn(mMetricsService).when(deps).getMetricsLogger(); doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); From b741c646c69ebdcfbc3287297a312a4ee1aeb5fe Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 27 Nov 2019 21:20:33 +0800 Subject: [PATCH 3/3] [Tether10]Remove UserManagerInternal usage in Tethering To be the unbundled application, tethering can not use UserManagerInternal method anymore. Replace it by listening user restriction change intent. Also fix some cleanup from https://android-review.googlesource.com/c/platform/frameworks/base/+/1131002 Bug: 143195885 Test: -build, flash, boot -atest TetheringTests -manual test. Add a trigger point to call UserManager.setUserRestriction(DISALLOW_CONFIG_TETHERING) from Settings. Open hotspot -> restrict tethering from new adding trigger point -> hotspot is OFF and Tethering settings are not available. Change-Id: I4ed08d20f8b7476b8ecd5d018b75806dd2f22cc1 Merged-In: I4ed08d20f8b7476b8ecd5d018b75806dd2f22cc1 --- core/java/android/os/ResultReceiver.aidl | 16 +++--- .../net/TetheringConfigurationParcel.aidl | 2 +- .../src/android/net/TetheringManager.java | 10 +++- .../connectivity/tethering/Tethering.java | 49 ++++++++++++------- .../connectivity/tethering/TetheringTest.java | 38 +++++++------- 5 files changed, 67 insertions(+), 48 deletions(-) diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl index 1ea6b43043d69..9fd5bc9704965 100644 --- a/core/java/android/os/ResultReceiver.aidl +++ b/core/java/android/os/ResultReceiver.aidl @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl index fdf0d16057b3c..89f38132ffadc 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl @@ -17,7 +17,7 @@ package android.net; /** - * Configuration details for a tethering. + * Configuration details for tethering. * @hide */ parcelable TetheringConfigurationParcel { diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 9e8726edf0e18..eb0d443f4bfc9 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -168,11 +168,12 @@ public class TetheringManager { * #getTetherableIfaces() to ensure corresponding interface is available for * tethering before calling #tether(). * - * TODO: Deprecate this API. The only usages should be in PanService and Wifi P2P which + * @deprecated The only usages should be in PanService and Wifi P2P which * need direct access. * * {@hide} */ + @Deprecated public int tether(@NonNull String iface) { try { mConnector.tether(iface); @@ -185,8 +186,10 @@ public class TetheringManager { /** * Stop tethering the named interface. * + * @deprecated * {@hide} */ + @Deprecated public int untether(@NonNull String iface) { try { mConnector.untether(iface); @@ -202,9 +205,10 @@ public class TetheringManager { * encapsulate proper entitlement logic. If the API is used and an entitlement check is needed, * downstream USB tethering will be enabled but will not have any upstream. * - * @Deprecated + * @deprecated * {@hide} */ + @Deprecated public int setUsbTethering(boolean enable) { try { mConnector.setUsbTethering(enable); @@ -386,8 +390,10 @@ public class TetheringManager { /** * Get the set of tethered dhcp ranges. * + * @deprecated This API just return the default value which is not used in DhcpServer. * {@hide} */ + @Deprecated public @NonNull String[] getTetheredDhcpRanges() { if (!mCallback.awaitCallbackCreation()) { throw new NullPointerException("callback was not ready yet"); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 058fb4fe98ca8..f1228129cd92e 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -93,8 +93,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; -import android.os.UserManagerInternal.UserRestrictionsListener; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -111,7 +109,6 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -188,6 +185,7 @@ public class Tethering { private final PhoneStateListener mPhoneStateListener; private final INetd mNetd; private final NetdCallback mNetdCallback; + private final UserRestrictionActionListener mTetheringRestriction; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetherInternalCallback should run in the same thread. private ITetherInternalCallback mTetherInternalCallback = null; @@ -280,6 +278,10 @@ public class Tethering { mLog.e("Unable to register netd UnsolicitedEventListener"); } + final UserManager userManager = (UserManager) mContext.getSystemService( + Context.USER_SERVICE); + mTetheringRestriction = new UserRestrictionActionListener(userManager, this); + // Load tethering configuration. updateConfiguration(); @@ -298,6 +300,7 @@ public class Tethering { filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, handler); filter = new IntentFilter(); @@ -306,11 +309,6 @@ public class Tethering { filter.addDataScheme("file"); mContext.registerReceiver(mStateReceiver, filter, null, handler); - final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); - // This check is useful only for some unit tests; example: ConnectivityServiceTest. - if (umi != null) { - umi.addUserRestrictionsListener(new TetheringUserRestrictionListener(this)); - } } private WifiManager getWifiManager() { @@ -717,8 +715,8 @@ public class Tethering { } if (mTetheredNotificationBuilder == null) { - mTetheredNotificationBuilder = - new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS); + mTetheredNotificationBuilder = new Notification.Builder(mContext, + SystemNotificationChannels.NETWORK_STATUS); mTetheredNotificationBuilder.setWhen(0) .setOngoing(true) .setColor(mContext.getColor( @@ -764,6 +762,9 @@ public class Tethering { } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { mLog.log("OBSERVED configuration changed"); updateConfiguration(); + } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) { + mLog.log("OBSERVED user restrictions changed"); + handleUserRestrictionAction(); } } @@ -870,25 +871,35 @@ public class Tethering { } } } + + private void handleUserRestrictionAction() { + mTetheringRestriction.onUserRestrictionsChanged(); + } } @VisibleForTesting - protected static class TetheringUserRestrictionListener implements UserRestrictionsListener { + protected static class UserRestrictionActionListener { + private final UserManager mUserManager; private final Tethering mWrapper; + public boolean mDisallowTethering; - public TetheringUserRestrictionListener(Tethering wrapper) { + public UserRestrictionActionListener(UserManager um, Tethering wrapper) { + mUserManager = um; mWrapper = wrapper; + mDisallowTethering = false; } - public void onUserRestrictionsChanged(int userId, - Bundle newRestrictions, - Bundle prevRestrictions) { + public void onUserRestrictionsChanged() { + // getUserRestrictions gets restriction for this process' user, which is the primary + // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary + // user. See UserManager.DISALLOW_CONFIG_TETHERING. + final Bundle restrictions = mUserManager.getUserRestrictions(); final boolean newlyDisallowed = - newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); - final boolean previouslyDisallowed = - prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); - final boolean tetheringDisallowedChanged = (newlyDisallowed != previouslyDisallowed); + restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); + final boolean prevDisallowed = mDisallowTethering; + mDisallowTethering = newlyDisallowed; + final boolean tetheringDisallowedChanged = (newlyDisallowed != prevDisallowed); if (!tetheringDisallowedChanged) { return; } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 4f6f61bf95d69..0273ed3586737 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -166,6 +166,7 @@ public class TetheringTest { @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon; @Mock private IDhcpServer mDhcpServer; @Mock private INetd mNetd; + @Mock private UserManager mUserManager; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -214,6 +215,7 @@ public class TetheringTest { if (Context.WIFI_SERVICE.equals(name)) return mWifiManager; if (Context.USB_SERVICE.equals(name)) return mUsbManager; if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager; + if (Context.USER_SERVICE.equals(name)) return mUserManager; return super.getSystemService(name); } @@ -954,26 +956,26 @@ public class TetheringTest { verifyNoMoreInteractions(mNMService); } - private void userRestrictionsListenerBehaviour( + private void runUserRestrictionsChange( boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, int expectedInteractionsWithShowNotification) throws Exception { - final int userId = 0; - final Bundle currRestrictions = new Bundle(); final Bundle newRestrictions = new Bundle(); - Tethering tethering = mock(Tethering.class); - Tethering.TetheringUserRestrictionListener turl = - new Tethering.TetheringUserRestrictionListener(tethering); - - currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow); newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow); - when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList); + final Tethering mockTethering = mock(Tethering.class); + when(mockTethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList); + when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions); - turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions); + final Tethering.UserRestrictionActionListener ural = + new Tethering.UserRestrictionActionListener(mUserManager, mockTethering); + ural.mDisallowTethering = currentDisallow; - verify(tethering, times(expectedInteractionsWithShowNotification)) + ural.onUserRestrictionsChanged(); + + verify(mockTethering, times(expectedInteractionsWithShowNotification)) .showTetheredNotification(anyInt(), eq(false)); - verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll(); + verify(mockTethering, times(expectedInteractionsWithShowNotification)) + .untetherAll(); } @Test @@ -983,7 +985,7 @@ public class TetheringTest { final boolean nextDisallow = true; final int expectedInteractionsWithShowNotification = 0; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList, expectedInteractionsWithShowNotification); } @@ -994,7 +996,7 @@ public class TetheringTest { final boolean nextDisallow = true; final int expectedInteractionsWithShowNotification = 1; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, expectedInteractionsWithShowNotification); } @@ -1005,7 +1007,7 @@ public class TetheringTest { final boolean nextDisallow = false; final int expectedInteractionsWithShowNotification = 0; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, expectedInteractionsWithShowNotification); } @@ -1016,7 +1018,7 @@ public class TetheringTest { final boolean nextDisallow = false; final int expectedInteractionsWithShowNotification = 0; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, expectedInteractionsWithShowNotification); } @@ -1027,13 +1029,13 @@ public class TetheringTest { boolean currDisallow = true; boolean nextDisallow = true; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, expectedInteractionsWithShowNotification); currDisallow = false; nextDisallow = false; - userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList, expectedInteractionsWithShowNotification); }