diff --git a/api/system-current.txt b/api/system-current.txt index a2bd999dd8035..675d20cb7d96a 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6095,8 +6095,8 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi(); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); - method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider); method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback); @@ -6112,10 +6112,10 @@ package android.net { field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd } - public abstract static class ConnectivityManager.OnStartTetheringCallback { - ctor public ConnectivityManager.OnStartTetheringCallback(); - method public void onTetheringFailed(); - method public void onTetheringStarted(); + @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback { + ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback(); + method @Deprecated public void onTetheringFailed(); + method @Deprecated public void onTetheringStarted(); } @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener { @@ -6523,11 +6523,13 @@ package android.net { } public class TetheringManager { - method public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); - method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); - method public void stopAllTethering(); - method public void stopTethering(int); - method public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; @@ -6560,6 +6562,12 @@ package android.net { method public void onTetheringEntitlementResult(int); } + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + public abstract static class TetheringManager.TetheringEventCallback { ctor public TetheringManager.TetheringEventCallback(); method public void onError(@NonNull String, int); @@ -6577,6 +6585,17 @@ package android.net { method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); } + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress); + } + public class TrafficStats { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); diff --git a/api/test-current.txt b/api/test-current.txt index e6e87791f258e..259d401c2adac 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1727,11 +1727,13 @@ package android.net { } public class TetheringManager { - method public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); - method @RequiresPermission("android.permission.TETHER_PRIVILEGED") public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); - method public void stopAllTethering(); - method public void stopTethering(int); - method public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; @@ -1764,6 +1766,12 @@ package android.net { method public void onTetheringEntitlementResult(int); } + public abstract static class TetheringManager.StartTetheringCallback { + ctor public TetheringManager.StartTetheringCallback(); + method public void onTetheringFailed(int); + method public void onTetheringStarted(); + } + public abstract static class TetheringManager.TetheringEventCallback { ctor public TetheringManager.TetheringEventCallback(); method public void onError(@NonNull String, int); @@ -1781,6 +1789,17 @@ package android.net { method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); } + public static class TetheringManager.TetheringRequest { + } + + public static class TetheringManager.TetheringRequest.Builder { + ctor public TetheringManager.TetheringRequest.Builder(int); + method @NonNull public android.net.TetheringManager.TetheringRequest build(); + method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); + method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean); + method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress); + } + public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3d6cae205b670..ce9693d88a977 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -33,7 +33,9 @@ import android.content.Context; import android.content.Intent; import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.SocketKeepalive.Callback; +import android.net.TetheringManager.StartTetheringCallback; import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringRequest; import android.os.Binder; import android.os.Build; import android.os.Build.VERSION_CODES; @@ -2452,10 +2454,12 @@ public class ConnectivityManager { * * @param iface the interface name to tether. * @return error a {@code TETHER_ERROR} value indicating success or failure type + * @deprecated Use {@link TetheringManager#startTethering} instead * * {@hide} */ @UnsupportedAppUsage + @Deprecated public int tether(String iface) { return getTetheringManager().tether(iface); } @@ -2512,9 +2516,12 @@ public class ConnectivityManager { /** * Callback for use with {@link #startTethering} to find out whether tethering succeeded. + * + * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead. * @hide */ @SystemApi + @Deprecated public static abstract class OnStartTetheringCallback { /** * Called when tethering has been successfully started. @@ -2531,9 +2538,12 @@ public class ConnectivityManager { * Convenient overload for * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null * handler to run on the current thread's {@link Looper}. + * + * @deprecated Use {@link TetheringManager#startTethering} instead. * @hide */ @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int type, boolean showProvisioningUi, final OnStartTetheringCallback callback) { @@ -2557,26 +2567,44 @@ public class ConnectivityManager { * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller * of the result of trying to tether. * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * + * @deprecated Use {@link TetheringManager#startTethering} instead. * @hide */ @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int type, boolean showProvisioningUi, final OnStartTetheringCallback callback, Handler handler) { Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null."); - ResultReceiver wrappedCallback = new ResultReceiver(handler) { + final Executor executor = new Executor() { @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == TETHER_ERROR_NO_ERROR) { - callback.onTetheringStarted(); + public void execute(Runnable command) { + if (handler == null) { + command.run(); } else { - callback.onTetheringFailed(); + handler.post(command); } } }; - getTetheringManager().startTethering(type, wrappedCallback, showProvisioningUi); + final StartTetheringCallback tetheringCallback = new StartTetheringCallback() { + @Override + public void onTetheringStarted() { + callback.onTetheringStarted(); + } + + @Override + public void onTetheringFailed(final int resultCode) { + callback.onTetheringFailed(); + } + }; + + final TetheringRequest request = new TetheringRequest.Builder(type) + .setSilentProvisioning(!showProvisioningUi).build(); + + getTetheringManager().startTethering(request, executor, tetheringCallback); } /** @@ -2749,10 +2777,12 @@ public class ConnectivityManager { * * @param enable a boolean - {@code true} to enable tethering * @return error a {@code TETHER_ERROR} value indicating success or failure type + * @deprecated Use {@link TetheringManager#startTethering} instead * * {@hide} */ @UnsupportedAppUsage + @Deprecated public int setUsbTethering(boolean enable) { return getTetheringManager().setUsbTethering(enable); } diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index a8d1239a3c309..b0ef153994359 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -70,6 +70,7 @@ filegroup { "src/android/net/ITetheringConnector.aidl", "src/android/net/TetheringCallbackStartedParcel.aidl", "src/android/net/TetheringConfigurationParcel.aidl", + "src/android/net/TetheringRequestParcel.aidl", "src/android/net/TetherStatesParcel.aidl", ], path: "src" diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index d30c399869849..5febe73288bf1 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.IIntResultListener; import android.net.ITetheringEventCallback; +import android.net.TetheringRequestParcel; import android.os.ResultReceiver; /** @hide */ @@ -27,8 +28,8 @@ oneway interface ITetheringConnector { void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver); - void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi, - String callerPkg); + void startTethering(in TetheringRequestParcel request, String callerPkg, + IIntResultListener receiver); void stopTethering(int type, String callerPkg, IIntResultListener receiver); diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index e1b9c16b8185b..58bc4e7633ce5 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -15,6 +15,7 @@ */ package android.net; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -325,28 +326,172 @@ public class TetheringManager { }); } + /** + * Use with {@link #startTethering} to specify additional parameters when starting tethering. + */ + public static class TetheringRequest { + /** A configuration set for TetheringRequest. */ + private final TetheringRequestParcel mRequestParcel; + + private TetheringRequest(final TetheringRequestParcel request) { + mRequestParcel = request; + } + + /** Builder used to create TetheringRequest. */ + public static class Builder { + private final TetheringRequestParcel mBuilderParcel; + + /** Default constructor of Builder. */ + public Builder(final int type) { + mBuilderParcel = new TetheringRequestParcel(); + mBuilderParcel.tetheringType = type; + mBuilderParcel.localIPv4Address = null; + mBuilderParcel.exemptFromEntitlementCheck = false; + mBuilderParcel.showProvisioningUi = true; + } + + /** + * Configure tethering with static IPv4 assignment (with DHCP disabled). + * + * @param localIPv4Address The preferred local IPv4 address to use. + */ + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + @NonNull + public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) { + mBuilderParcel.localIPv4Address = localIPv4Address; + return this; + } + + /** Start tethering without entitlement checks. */ + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + @NonNull + public Builder setExemptFromEntitlementCheck(boolean exempt) { + mBuilderParcel.exemptFromEntitlementCheck = exempt; + return this; + } + + /** Start tethering without showing the provisioning UI. */ + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + @NonNull + public Builder setSilentProvisioning(boolean silent) { + mBuilderParcel.showProvisioningUi = silent; + return this; + } + + /** Build {@link TetheringRequest] with the currently set configuration. */ + @NonNull + public TetheringRequest build() { + return new TetheringRequest(mBuilderParcel); + } + } + + /** + * Get a TetheringRequestParcel from the configuration + * @hide + */ + public TetheringRequestParcel getParcel() { + return mRequestParcel; + } + + /** String of TetheringRequest detail. */ + public String toString() { + return "TetheringRequest [ type= " + mRequestParcel.tetheringType + + ", localIPv4Address= " + mRequestParcel.localIPv4Address + + ", exemptFromEntitlementCheck= " + + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= " + + mRequestParcel.showProvisioningUi + " ]"; + } + } + + /** + * Callback for use with {@link #startTethering} to find out whether tethering succeeded. + */ + public abstract static class StartTetheringCallback { + /** + * Called when tethering has been successfully started. + */ + public void onTetheringStarted() {} + + /** + * Called when starting tethering failed. + * + * @param resultCode One of the {@code TETHER_ERROR_*} constants. + */ + public void onTetheringFailed(final int resultCode) {} + } + /** * Starts tethering and runs tether provisioning for the given type if needed. If provisioning * fails, stopTethering will be called automatically. - * @hide + * + *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will + * fail if a tethering entitlement check is required. + * + * @param request a {@link TetheringRequest} which can specify the preferred configuration. + * @param executor {@link Executor} to specify the thread upon which the callback of + * TetheringRequest will be invoked. + * @param callback A callback that will be called to indicate the success status of the + * tethering start request. */ - // TODO: improve the usage of ResultReceiver, b/145096122 - public void startTethering(final int type, @NonNull final ResultReceiver receiver, - final boolean showProvisioningUi) { + @RequiresPermission(anyOf = { + android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS + }) + public void startTethering(@NonNull final TetheringRequest request, + @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "startTethering caller:" + callerPkg); + final IIntResultListener listener = new IIntResultListener.Stub() { + @Override + public void onResult(final int resultCode) { + executor.execute(() -> { + if (resultCode == TETHER_ERROR_NO_ERROR) { + callback.onTetheringStarted(); + } else { + callback.onTetheringFailed(resultCode); + } + }); + } + }; try { - mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg); + mConnector.startTethering(request.getParcel(), callerPkg, listener); } catch (RemoteException e) { throw new IllegalStateException(e); } } + /** + * Starts tethering and runs tether provisioning for the given type if needed. If provisioning + * fails, stopTethering will be called automatically. + * + *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will + * fail if a tethering entitlement check is required. + * + * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants. + * @param executor {@link Executor} to specify the thread upon which the callback of + * TetheringRequest will be invoked. + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS + }) + public void startTethering(int type, @NonNull final Executor executor, + @NonNull final StartTetheringCallback callback) { + startTethering(new TetheringRequest.Builder(type).build(), executor, callback); + } + /** * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if * applicable. + * + *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will + * fail if a tethering entitlement check is required. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS + }) public void stopTethering(final int type) { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopTethering caller:" + callerPkg); @@ -386,6 +531,9 @@ public class TetheringManager { * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is * true, entitlement will be run. * + *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will + * fail if a tethering entitlement check is required. + * * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants. * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check. * @param executor the executor on which callback will be invoked. @@ -393,7 +541,10 @@ public class TetheringManager { * notify the caller of the result of entitlement check. The listener may be called zero * or one time. */ - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + @RequiresPermission(anyOf = { + android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS + }) public void requestLatestTetheringEntitlementResult(int type, boolean showEntitlementUi, @NonNull Executor executor, @NonNull final OnTetheringEntitlementResultListener listener) { @@ -562,6 +713,7 @@ public class TetheringManager { * @param executor the executor on which callback will be invoked. * @param callback the callback to be called when tethering has change events. */ + @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull Executor executor, @NonNull TetheringEventCallback callback) { final String callerPkg = mContext.getOpPackageName(); @@ -669,6 +821,10 @@ public class TetheringManager { * * @param callback previously registered callback. */ + @RequiresPermission(anyOf = { + Manifest.permission.TETHER_PRIVILEGED, + Manifest.permission.ACCESS_NETWORK_STATE + }) public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg); @@ -833,7 +989,14 @@ public class TetheringManager { /** * Stop all active tethering. + * + *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will + * fail if a tethering entitlement check is required. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS + }) public void stopAllTethering() { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopAllTethering caller:" + callerPkg); diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl new file mode 100644 index 0000000000000..bf19d85f6a836 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 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.LinkAddress; + +/** + * Configuration details for requesting tethering. + * @hide + */ +parcelable TetheringRequestParcel { + int tetheringType; + LinkAddress localIPv4Address; + boolean exemptFromEntitlementCheck; + boolean showProvisioningUi; +} diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 5370145f1992c..c47f2d6d4db21 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -66,6 +66,7 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; +import android.net.IIntResultListener; import android.net.INetd; import android.net.ITetheringEventCallback; import android.net.IpPrefix; @@ -76,6 +77,7 @@ import android.net.NetworkInfo; import android.net.TetherStatesParcel; import android.net.TetheringCallbackStartedParcel; import android.net.TetheringConfigurationParcel; +import android.net.TetheringRequestParcel; import android.net.ip.IpServer; import android.net.shared.NetdUtils; import android.net.util.BaseNetdUnsolicitedEventListener; @@ -424,9 +426,10 @@ public class Tethering { } } - void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { - mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi); - enableTetheringInternal(type, true /* enabled */, receiver); + void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) { + mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType, + request.showProvisioningUi); + enableTetheringInternal(request.tetheringType, true /* enabled */, listener); } void stopTethering(int type) { @@ -438,29 +441,32 @@ public class Tethering { * Enables or disables tethering for the given type. If provisioning is required, it will * schedule provisioning rechecks for the specified interface. */ - private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) { + private void enableTetheringInternal(int type, boolean enable, + final IIntResultListener listener) { int result; switch (type) { case TETHERING_WIFI: result = setWifiTethering(enable); - sendTetherResult(receiver, result); + sendTetherResult(listener, result); break; case TETHERING_USB: result = setUsbTethering(enable); - sendTetherResult(receiver, result); + sendTetherResult(listener, result); break; case TETHERING_BLUETOOTH: - setBluetoothTethering(enable, receiver); + setBluetoothTethering(enable, listener); break; default: Log.w(TAG, "Invalid tether type."); - sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE); + sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE); } } - private void sendTetherResult(ResultReceiver receiver, int result) { - if (receiver != null) { - receiver.send(result, null); + private void sendTetherResult(final IIntResultListener listener, int result) { + if (listener != null) { + try { + listener.onResult(result); + } catch (RemoteException e) { } } } @@ -486,12 +492,12 @@ public class Tethering { return TETHER_ERROR_MASTER_ERROR; } - private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { + private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) { final BluetoothAdapter adapter = mDeps.getBluetoothAdapter(); if (adapter == null || !adapter.isEnabled()) { Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + (adapter == null)); - sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL); + sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL); return; } @@ -520,7 +526,7 @@ public class Tethering { final int result = (((BluetoothPan) proxy).isTetheringOn() == enable) ? TETHER_ERROR_NO_ERROR : TETHER_ERROR_MASTER_ERROR; - sendTetherResult(receiver, result); + sendTetherResult(listener, result); adapter.closeProfileProxy(BluetoothProfile.PAN, proxy); } }, BluetoothProfile.PAN); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index cb7d3920e693f..7dc5c5f2db8aa 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -33,6 +33,7 @@ import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.ip.IpServer; @@ -143,11 +144,11 @@ public class TetheringService extends Service { } @Override - public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi, - String callerPkg) { - if (checkAndNotifyCommonError(callerPkg, receiver)) return; + public void startTethering(TetheringRequestParcel request, String callerPkg, + IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; - mTethering.startTethering(type, receiver, showProvisioningUi); + mTethering.startTethering(request, listener); } @Override diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 9f0d8769b1f97..6fc0c659f3979 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -88,6 +88,7 @@ import android.net.RouteInfo; import android.net.TetherStatesParcel; import android.net.TetheringCallbackStartedParcel; import android.net.TetheringConfigurationParcel; +import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServer; @@ -468,6 +469,16 @@ public class TetheringTest { return new Tethering(mTetheringDependencies); } + private TetheringRequestParcel createTetheringRquestParcel(final int type) { + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = type; + request.localIPv4Address = null; + request.exemptFromEntitlementCheck = false; + request.showProvisioningUi = false; + + return request; + } + @After public void tearDown() { mServiceContext.unregisterReceiver(mBroadcastReceiver); @@ -573,7 +584,7 @@ public class TetheringTest { .thenReturn(upstreamState); // Emulate pressing the USB tethering button in Settings UI. - mTethering.startTethering(TETHERING_USB, null, false); + mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null); mLooper.dispatchAll(); verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); @@ -819,7 +830,7 @@ public class TetheringTest { when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(TETHERING_WIFI, null, false); + mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); @@ -846,7 +857,7 @@ public class TetheringTest { when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(TETHERING_WIFI, null, false); + mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); @@ -923,7 +934,7 @@ public class TetheringTest { doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME); // Emulate pressing the WiFi tethering button. - mTethering.startTethering(TETHERING_WIFI, null, false); + mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); @@ -1188,7 +1199,7 @@ public class TetheringTest { tetherState = callback.pollTetherStatesChanged(); assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); - mTethering.startTethering(TETHERING_WIFI, null, false); + mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null); sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); tetherState = callback.pollTetherStatesChanged();