diff options
36 files changed, 1636 insertions, 414 deletions
| diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl index 28ce6d5f15b0..9fd5bc970496 100644 --- a/core/java/android/os/ResultReceiver.aidl +++ b/core/java/android/os/ResultReceiver.aidl @@ -2,19 +2,19 @@  **  ** 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.  */  package android.os; -parcelable ResultReceiver; +@JavaOnlyStableParcelable parcelable ResultReceiver; diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 7b35f4d56a7a..7e8721d3cc70 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",      ], @@ -41,20 +40,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 +69,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 +78,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: [ @@ -83,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 { @@ -96,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 eb51593e4538..1430ed00aa91 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"> +        <service android:name="com.android.server.connectivity.tethering.TetheringService" +                 android:permission="android.permission.MAINLINE_NETWORK_STACK"> +            <intent-filter> +                <action android:name="android.net.ITetheringConnector"/> +            </intent-filter> +        </service>      </application>  </manifest> diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml new file mode 100644 index 000000000000..28d405c3133a --- /dev/null +++ b/packages/Tethering/AndroidManifest_InProcess.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +          package="com.android.tethering.inprocess" +          android:sharedUserId="android.uid.system" +          android:process="system"> +    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> +    <application> +        <!-- TODO: Using MAINLINE_NETWORK_STACK instead of NETWORK_STACK when tethering run in the +                   same process with networkstack --> +        <service android:name="com.android.server.connectivity.tethering.TetheringService" +                 android:process="system" +                 android:permission="android.permission.NETWORK_STACK"> +            <intent-filter> +                <action android:name="android.net.ITetheringConnector.InProcess"/> +            </intent-filter> +        </service> +    </application> +</manifest> diff --git a/packages/Tethering/CleanSpec.mk b/packages/Tethering/CleanSpec.mk new file mode 100644 index 000000000000..70db351a6928 --- /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/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 5b01b1e038c3..adc5a723a960 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 000000000000..abb00e819f50 --- /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 443481e33f8d..bfe502fbeb11 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 000000000000..3d842b337428 --- /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 000000000000..89f38132ffad --- /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 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 000000000000..eb0d443f4bfc --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -0,0 +1,513 @@ +/* + * 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<ITetheringEventCallback> 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. +     * +     * <p>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(). +     * +     * @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); +        } catch (RemoteException e) { +            e.rethrowFromSystemServer(); +        } +        return TETHER_ERROR_NO_ERROR; +    } + +    /** +     * Stop tethering the named interface. +     * +     * @deprecated +     * {@hide} +     */ +    @Deprecated +    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} +     */ +    @Deprecated +    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. +     * +     * @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"); +        } +        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 3eaf48845a2f..663154a49048 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<void**>(&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 000000000000..3218c0b387bb --- /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 index 107c40495f9e..e2804abd752b 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<Intent> callback) { +        Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> 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 6b0f1de7ce85..ba5d08dce4ca 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<Integer> 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<Integer>();          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 index 81863439c017..edfe3cad9039 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 01339a4a2c33..00a677338b1b 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 index acedc3635730..f1228129cd92 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,13 +89,10 @@ 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;  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; @@ -110,15 +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 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 +117,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<String> 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 +167,7 @@ public class Tethering extends BaseNetworkObserver {      private final Context mContext;      private final ArrayMap<String, TetherState> mTetherStates;      private final BroadcastReceiver mStateReceiver; +    // Stopship: replace mNMService before production.      private final INetworkManagementService mNMService;      private final INetworkStatsService mStatsService;      private final INetworkPolicyManager mPolicyManager; @@ -191,10 +182,13 @@ public class Tethering extends BaseNetworkObserver {      private final TetheringDependencies mDeps;      private final EntitlementManager mEntitlementMgr;      private final Handler mHandler; -    private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks = -            new RemoteCallbackList<>();      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;      private volatile TetheringConfiguration mConfig;      private InterfaceSet mCurrentUpstreamIfaceSet; @@ -205,18 +199,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 +232,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 +271,22 @@ 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"); +        } + +        final UserManager userManager = (UserManager) mContext.getSystemService( +                    Context.USER_SERVICE); +        mTetheringRestriction = new UserRestrictionActionListener(userManager, this); +          // Load tethering configuration.          updateConfiguration();          startStateMachineUpdaters(mHandler); +        startTrackDefaultNetwork();      }      private void startStateMachineUpdaters(Handler handler) { @@ -295,6 +300,7 @@ public class Tethering extends BaseNetworkObserver {          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(); @@ -303,11 +309,6 @@ public class Tethering extends BaseNetworkObserver {          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() { @@ -318,6 +319,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 +329,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 +372,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 +391,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 +455,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 +471,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 +508,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 +536,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 +553,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 +580,14 @@ public class Tethering extends BaseNetworkObserver {          final ArrayList<String> tetherList = new ArrayList<>();          final ArrayList<String> localOnlyList = new ArrayList<>();          final ArrayList<String> erroredList = new ArrayList<>(); +        final ArrayList<Integer> 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 +595,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 +612,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<Integer> 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 +674,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) { @@ -679,8 +715,8 @@ public class Tethering extends BaseNetworkObserver {          }          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( @@ -701,7 +737,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); @@ -726,14 +762,17 @@ public class Tethering extends BaseNetworkObserver {              } 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();              }          }          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;              } @@ -832,25 +871,35 @@ public class Tethering extends BaseNetworkObserver {                  }              }          } + +        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;              } @@ -888,8 +937,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 +977,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 +1038,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 +1056,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 +1084,7 @@ public class Tethering extends BaseNetworkObserver {      }      // TODO review API - figure out how to delete these entirely. -    public String[] getTetheredIfaces() { +    String[] getTetheredIfaces() {          ArrayList<String> list = new ArrayList<String>();          synchronized (mPublicSync) {              for (int i = 0; i < mTetherStates.size(); i++) { @@ -1048,7 +1097,7 @@ public class Tethering extends BaseNetworkObserver {          return list.toArray(new String[list.size()]);      } -    public String[] getTetherableIfaces() { +    String[] getTetherableIfaces() {          ArrayList<String> list = new ArrayList<String>();          synchronized (mPublicSync) {              for (int i = 0; i < mTetherStates.size(); i++) { @@ -1061,13 +1110,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<String> list = new ArrayList<String>();          synchronized (mPublicSync) {              for (int i = 0; i < mTetherStates.size(); i++) { @@ -1518,8 +1567,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 +1637,7 @@ public class Tethering extends BaseNetworkObserver {                          transitionTo(mInitialState);                          break;                      default: -                       retValue = false; +                        retValue = false;                  }                  return retValue;              } @@ -1625,7 +1674,7 @@ public class Tethering extends BaseNetworkObserver {                  notify(IpServer.CMD_START_TETHERING_ERROR);                  try {                      mNMService.setIpForwardingEnabled(false); -                } catch (Exception e) {} +                } catch (Exception e) { }              }          } @@ -1636,7 +1685,7 @@ public class Tethering extends BaseNetworkObserver {                  notify(IpServer.CMD_STOP_TETHERING_ERROR);                  try {                      mNMService.setIpForwardingEnabled(false); -                } catch (Exception e) {} +                } catch (Exception e) { }              }          } @@ -1647,10 +1696,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 +1780,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) { +        // Don't need to synchronized mTetherInternalCallback because all the usage of this variable +        // should run at the same thread. +        if (mTetherInternalCallback == null) return; + +        try { +            mTetherInternalCallback.onUpstreamChanged(network); +        } catch (RemoteException e) { +            // Not really very much to do here. +        }      } -    private void reportUpstreamChanged(Network network) { -        final int length = mTetheringEventCallbacks.beginBroadcast(); +    private void reportConfigurationChanged(TetheringConfigurationParcel config) { +        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.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.          }      } -    @Override -    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { +    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 +1898,7 @@ public class Tethering extends BaseNetworkObserver {          pw.println("Log:");          pw.increaseIndent(); -        if (argsContain(args, SHORT_ARG)) { +        if (argsContain(args, "--short")) {              pw.println("<log removed for brevity>");          } 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 ca9b1681bacc..0ab4d634e84d 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 index 4ad7ac4bead0..0ba84127d8da 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 index 0ef3805ff7c0..0ef3805ff7c0 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/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 000000000000..456f2f7f27f5 --- /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. + * + * <p>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 363be18a73bc..5b018df21aaf 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 index 0d27d5bf0a11..5a9b6e380ea9 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 5217e26a40ef..99cf9e90d912 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 index 9e5717b4bd64..0273ed358673 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; @@ -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()); @@ -184,28 +185,37 @@ 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) {              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);          } @@ -266,14 +276,14 @@ public class TetheringTest {      }      public class MockTetheringDependencies extends TetheringDependencies { -        StateMachine upstreamNetworkMonitorMasterSM; -        ArrayList<IpServer> ipv6CoordinatorNotifyList; -        int isTetheringSupportedCalls; +        StateMachine mUpstreamNetworkMonitorMasterSM; +        ArrayList<IpServer> mIpv6CoordinatorNotifyList; +        int mIsTetheringSupportedCalls;          public void reset() { -            upstreamNetworkMonitorMasterSM = null; -            ipv6CoordinatorNotifyList = null; -            isTetheringSupportedCalls = 0; +            mUpstreamNetworkMonitorMasterSM = null; +            mIpv6CoordinatorNotifyList = null; +            mIsTetheringSupportedCalls = 0;          }          @Override @@ -284,14 +294,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<IpServer> notifyList, SharedLog log) { -            ipv6CoordinatorNotifyList = notifyList; +            mIpv6CoordinatorNotifyList = notifyList;              return mIPv6TetheringCoordinator;          } @@ -302,7 +312,7 @@ public class TetheringTest {          @Override          public boolean isTetheringSupported() { -            isTetheringSupportedCalls++; +            mIsTetheringSupportedCalls++;              return true;          } @@ -311,6 +321,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 +385,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 +430,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 +443,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<PhoneStateListener> phoneListenerCaptor =                  ArgumentCaptor.forClass(PhoneStateListener.class);          verify(mTelephonyManager).listen(phoneListenerCaptor.capture(), @@ -414,9 +454,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 +546,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 +623,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 +656,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 +688,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 +757,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 +822,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 +866,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 +939,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); @@ -918,26 +956,26 @@ public class TetheringTest {          verifyNoMoreInteractions(mNMService);      } -    private void userRestrictionsListenerBehaviour( -        boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, -        int expectedInteractionsWithShowNotification) throws  Exception { -        final int userId = 0; -        final Bundle currRestrictions = new Bundle(); +    private void runUserRestrictionsChange( +            boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, +            int expectedInteractionsWithShowNotification) throws  Exception {          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 @@ -947,7 +985,7 @@ public class TetheringTest {          final boolean nextDisallow = true;          final int expectedInteractionsWithShowNotification = 0; -        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList, +        runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,                  expectedInteractionsWithShowNotification);      } @@ -958,7 +996,7 @@ public class TetheringTest {          final boolean nextDisallow = true;          final int expectedInteractionsWithShowNotification = 1; -        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, +        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,                  expectedInteractionsWithShowNotification);      } @@ -969,7 +1007,7 @@ public class TetheringTest {          final boolean nextDisallow = false;          final int expectedInteractionsWithShowNotification = 0; -        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, +        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,                  expectedInteractionsWithShowNotification);      } @@ -980,7 +1018,7 @@ public class TetheringTest {          final boolean nextDisallow = false;          final int expectedInteractionsWithShowNotification = 0; -        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, +        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,                  expectedInteractionsWithShowNotification);      } @@ -991,27 +1029,59 @@ 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);      } -    private class TestTetheringEventCallback extends ITetheringEventCallback.Stub { +    private class TestTetherInternalCallback extends ITetherInternalCallback.Stub {          private final ArrayList<Network> mActualUpstreams = new ArrayList<>(); - +        private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs = +                new ArrayList<>(); +        private final ArrayList<TetherStatesParcel> 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<Network> expectedUpstreams =                      new ArrayList<Network>(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<TetheringConfigurationParcel> expectedTetherConfig = +                    new ArrayList<TetheringConfigurationParcel>(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 +1089,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 +1206,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 084a74724ad8..4e75e006e111 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", @@ -50,7 +49,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", @@ -82,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 bb7406a56772..652dd40297b9 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);              }          }      }; @@ -2193,7 +2173,6 @@ public class ConnectivityService extends IConnectivityManager.Stub          mPermissionMonitor.startMonitoring();          mProxyTracker.loadGlobalProxy();          registerNetdEventCallback(); -        mTethering.systemReady();          synchronized (this) {              mSystemReady = true; @@ -2405,9 +2384,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; @@ -2469,10 +2445,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); @@ -4004,7 +3983,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;          } @@ -4016,7 +3995,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;          } @@ -4028,7 +4007,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          enforceTetherAccessPermission();          if (isTetheringSupported()) { -            return mTethering.getLastTetherError(iface); +            return mTetheringManager.getLastTetherError(iface);          } else {              return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;          } @@ -4039,7 +4018,7 @@ public class ConnectivityService extends IConnectivityManager.Stub      public String[] getTetherableUsbRegexs() {          enforceTetherAccessPermission();          if (isTetheringSupported()) { -            return mTethering.getTetherableUsbRegexs(); +            return mTetheringManager.getTetherableUsbRegexs();          } else {              return new String[0];          } @@ -4049,7 +4028,7 @@ public class ConnectivityService extends IConnectivityManager.Stub      public String[] getTetherableWifiRegexs() {          enforceTetherAccessPermission();          if (isTetheringSupported()) { -            return mTethering.getTetherableWifiRegexs(); +            return mTetheringManager.getTetherableWifiRegexs();          } else {              return new String[0];          } @@ -4059,7 +4038,7 @@ public class ConnectivityService extends IConnectivityManager.Stub      public String[] getTetherableBluetoothRegexs() {          enforceTetherAccessPermission();          if (isTetheringSupported()) { -            return mTethering.getTetherableBluetoothRegexs(); +            return mTetheringManager.getTetherableBluetoothRegexs();          } else {              return new String[0];          } @@ -4069,7 +4048,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;          } @@ -4080,25 +4059,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 @@ -4126,7 +4105,8 @@ public class ConnectivityService extends IConnectivityManager.Stub              Binder.restoreCallingIdentity(token);          } -        return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration(); +        return tetherEnabledInSettings && adminUser +                && mTetheringManager.hasTetherableConfiguration();      }      @Override @@ -4137,13 +4117,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);      }      /** @@ -4157,7 +4137,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. */ @@ -4165,7 +4146,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. */ @@ -4173,7 +4154,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 08c94267e969..e473c96980b6 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 7b3fbb97da56..2b1c07ba40b1 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 efffa6ca735b..692c9d25baa9 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 def61bf88798..adf3218e42d3 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; @@ -2175,6 +2176,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 45430eab9bf4..2dabdb7d47de 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 10f27e243c8c..b2f384ac8360 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 334b26d82129..25028fb3ca0e 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 7ea9bcf36f91..2a09f647a46b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -163,6 +163,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; @@ -210,7 +211,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; @@ -1130,7 +1130,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()); |