diff options
author | markchien <markchien@google.com> | 2019-12-16 20:15:20 +0800 |
---|---|---|
committer | markchien <markchien@google.com> | 2019-12-20 10:31:31 +0800 |
commit | ae8aa646dc809e714af45369d9409f63ea367b2c (patch) | |
tree | b0055a73410d13f221aea2a41fd6d10dee635fff | |
parent | 6af4789825dd28fd516df963203965564a004936 (diff) |
[Tether13] Move TetheringManager into framework
Move tethering out of ConnectivityService. All client would
use TetheringManager to talk with TetheringService directly.
Bug: 144320246
Test: -build, flash, boot
-atest TetheringTests
Change-Id: Ib051bea724a256f9c4572b566e46ae7b9c4abe6e
35 files changed, 927 insertions, 829 deletions
diff --git a/Android.bp b/Android.bp index eef9f8084ca8..536f6885bd13 100644 --- a/Android.bp +++ b/Android.bp @@ -264,6 +264,7 @@ filegroup { ":framework-appsearch-sources", ":framework-sdkext-sources", ":framework-statsd-sources", + ":framework-tethering-srcs", ":updatable-media-srcs", ":framework-mediaprovider-sources", ":framework-wifi-updatable-sources", @@ -382,6 +383,7 @@ java_defaults { "unsupportedappusage", "updatable_media_stubs", "framework_mediaprovider_stubs", + "framework-tethering", ], jarjar_rules: ":framework-jarjar-rules", @@ -627,10 +629,26 @@ filegroup { ], } +// keep these files in sync with the package/Tethering/jarjar-rules.txt for the tethering module. filegroup { name: "framework-tethering-shared-srcs", srcs: [ "core/java/android/util/LocalLog.java", + "core/java/com/android/internal/util/BitUtils.java", + "core/java/com/android/internal/util/IndentingPrintWriter.java", + "core/java/com/android/internal/util/IState.java", + "core/java/com/android/internal/util/MessageUtils.java", + "core/java/com/android/internal/util/Preconditions.java", + "core/java/com/android/internal/util/State.java", + "core/java/com/android/internal/util/StateMachine.java", + ], +} + +filegroup { + name: "framework-tethering-annotations", + srcs: [ + "core/java/android/annotation/NonNull.java", + "core/java/android/annotation/SystemApi.java", ], } // Build ext.jar diff --git a/api/system-current.txt b/api/system-current.txt index d51b46dc6845..a97f46499dd5 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1655,6 +1655,7 @@ package android.content { field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry"; + field public static final String TETHERING_SERVICE = "tethering"; field public static final String VR_SERVICE = "vrmanager"; field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager"; field public static final String WIFI_SCANNING_SERVICE = "wifiscanner"; @@ -7445,6 +7446,7 @@ package android.provider { field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis"; field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt"; + field public static final String TETHER_SUPPORTED = "tether_supported"; field public static final String THEATER_MODE_ON = "theater_mode_on"; field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; field public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds"; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index ce21db335615..41d3ce42f6a7 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -116,6 +116,7 @@ import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; import android.net.NetworkWatchlistManager; import android.net.TestNetworkManager; +import android.net.TetheringManager; import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; import android.net.nsd.INsdManager; @@ -339,6 +340,17 @@ public final class SystemServiceRegistry { } }); + registerService(Context.TETHERING_SERVICE, TetheringManager.class, + new CachedServiceFetcher<TetheringManager>() { + @Override + public TetheringManager createService(ContextImpl ctx) throws ServiceNotFoundException { + IBinder b = ServiceManager.getService(Context.TETHERING_SERVICE); + if (b == null) return null; + + return new TetheringManager(ctx, b); + }}); + + registerService(Context.IPSEC_SERVICE, IpSecManager.class, new CachedServiceFetcher<IpSecManager>() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 66abf5d4eb6f..483bf3f1ec87 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3932,6 +3932,15 @@ public abstract class Context { public static final String NETWORK_STACK_SERVICE = "network_stack"; /** + * Use with {@link android.os.ServiceManager.getService()} to retrieve a + * {@link ITetheringConnector} IBinder for communicating with the tethering service + * @hide + * @see TetheringClient + */ + @SystemApi + public static final String TETHERING_SERVICE = "tethering"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.net.IpSecManager} for encrypting Sockets or Networks with * IPSec. diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index d95da91d2009..3ed51d7f13e4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -50,6 +50,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -57,7 +58,6 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; -import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.Protocol; @@ -802,6 +802,7 @@ public class ConnectivityManager { private INetworkManagementService mNMService; private INetworkPolicyManager mNPManager; + private TetheringManager mTetheringManager; /** * Tests if a given integer represents a valid network type. @@ -2339,6 +2340,28 @@ public class ConnectivityManager { return getInstanceOrNull(); } + private static final int TETHERING_TIMEOUT_MS = 60_000; + private final Object mTetheringLock = new Object(); + + private TetheringManager getTetheringManager() { + synchronized (mTetheringLock) { + if (mTetheringManager != null) { + return mTetheringManager; + } + final long before = System.currentTimeMillis(); + while ((mTetheringManager = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE)) == null) { + if (System.currentTimeMillis() - before > TETHERING_TIMEOUT_MS) { + Log.e(TAG, "Timeout waiting tethering service not ready yet"); + throw new IllegalStateException("No tethering service yet"); + } + SystemClock.sleep(100); + } + + return mTetheringManager; + } + } + /** * Get the set of tetherable, available interfaces. This list is limited by * device configuration and current interface existence. @@ -2350,11 +2373,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetherableIfaces() { - try { - return mService.getTetherableIfaces(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetherableIfaces(); } /** @@ -2367,11 +2386,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetheredIfaces() { - try { - return mService.getTetheredIfaces(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetheredIfaces(); } /** @@ -2390,11 +2405,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetheringErroredIfaces() { - try { - return mService.getTetheringErroredIfaces(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetheringErroredIfaces(); } /** @@ -2405,11 +2416,7 @@ public class ConnectivityManager { */ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getTetheredDhcpRanges() { - try { - return mService.getTetheredDhcpRanges(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetheredDhcpRanges(); } /** @@ -2438,13 +2445,7 @@ public class ConnectivityManager { */ @UnsupportedAppUsage public int tether(String iface) { - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "tether caller:" + pkgName); - return mService.tether(iface, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().tether(iface); } /** @@ -2467,13 +2468,7 @@ public class ConnectivityManager { */ @UnsupportedAppUsage public int untether(String iface) { - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "untether caller:" + pkgName); - return mService.untether(iface, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().untether(iface); } /** @@ -2498,16 +2493,7 @@ public class ConnectivityManager { @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported() { - String pkgName = mContext.getOpPackageName(); - try { - return mService.isTetheringSupported(pkgName); - } catch (SecurityException e) { - // This API is not available to this caller, but for backward-compatibility - // this will just return false instead of throwing. - return false; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().isTetheringSupported(); } /** @@ -2576,14 +2562,7 @@ public class ConnectivityManager { } }; - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "startTethering caller:" + pkgName); - mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName); - } catch (RemoteException e) { - Log.e(TAG, "Exception trying to start tethering.", e); - wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null); - } + getTetheringManager().startTethering(type, wrappedCallback, showProvisioningUi); } /** @@ -2599,13 +2578,7 @@ public class ConnectivityManager { @SystemApi @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int type) { - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "stopTethering caller:" + pkgName); - mService.stopTethering(type, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getTetheringManager().stopTethering(type); } /** @@ -2627,10 +2600,6 @@ public class ConnectivityManager { public void onUpstreamChanged(@Nullable Network network) {} } - @GuardedBy("mTetheringEventCallbacks") - private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback> - mTetheringEventCallbacks = new ArrayMap<>(); - /** * Start listening to tethering change events. Any new added callback will receive the last * tethering status right away. If callback is registered when tethering has no upstream or @@ -2648,27 +2617,7 @@ public class ConnectivityManager { @NonNull final OnTetheringEventCallback callback) { Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null."); - synchronized (mTetheringEventCallbacks) { - Preconditions.checkArgument(!mTetheringEventCallbacks.containsKey(callback), - "callback was already registered."); - ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() { - @Override - public void onUpstreamChanged(Network network) throws RemoteException { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - callback.onUpstreamChanged(network); - })); - } - }; - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "registerTetheringUpstreamCallback:" + pkgName); - mService.registerTetheringEventCallback(remoteCallback, pkgName); - mTetheringEventCallbacks.put(callback, remoteCallback); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + getTetheringManager().registerTetheringEventCallback(executor, callback); } /** @@ -2682,17 +2631,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback( @NonNull final OnTetheringEventCallback callback) { - synchronized (mTetheringEventCallbacks) { - ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback); - Preconditions.checkNotNull(remoteCallback, "callback was not registered."); - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "unregisterTetheringEventCallback:" + pkgName); - mService.unregisterTetheringEventCallback(remoteCallback, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + getTetheringManager().unregisterTetheringEventCallback(callback); } @@ -2709,11 +2648,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetherableUsbRegexs() { - try { - return mService.getTetherableUsbRegexs(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetherableUsbRegexs(); } /** @@ -2729,11 +2664,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetherableWifiRegexs() { - try { - return mService.getTetherableWifiRegexs(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetherableWifiRegexs(); } /** @@ -2749,11 +2680,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public String[] getTetherableBluetoothRegexs() { - try { - return mService.getTetherableBluetoothRegexs(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getTetherableBluetoothRegexs(); } /** @@ -2775,13 +2702,7 @@ public class ConnectivityManager { */ @UnsupportedAppUsage public int setUsbTethering(boolean enable) { - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "setUsbTethering caller:" + pkgName); - return mService.setUsbTethering(enable, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().setUsbTethering(enable); } /** {@hide} */ @@ -2829,11 +2750,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public int getLastTetherError(String iface) { - try { - return mService.getLastTetherError(iface); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTetheringManager().getLastTetherError(iface); } /** @hide */ @@ -2899,14 +2816,8 @@ public class ConnectivityManager { } }; - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "getLatestTetheringEntitlementResult:" + pkgName); - mService.getLatestTetheringEntitlementResult(type, wrappedListener, - showEntitlementUi, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getTetheringManager().requestLatestTetheringEntitlementResult(type, wrappedListener, + showEntitlementUi); } /** @@ -4331,6 +4242,7 @@ public class ConnectivityManager { public void factoryReset() { try { mService.factoryReset(); + getTetheringManager().stopAllTethering(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 5f662f914919..09c02efbcfc4 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -19,7 +19,6 @@ package android.net; import android.app.PendingIntent; import android.net.ConnectionInfo; import android.net.LinkProperties; -import android.net.ITetheringEventCallback; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; @@ -78,41 +77,31 @@ interface IConnectivityManager boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); - int tether(String iface, String callerPkg); - - int untether(String iface, String callerPkg); - - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getLastTetherError} as alternative") int getLastTetherError(String iface); - boolean isTetheringSupported(String callerPkg); - - void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi, - String callerPkg); - - void stopTethering(int type, String callerPkg); - - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableIfaces} as alternative") String[] getTetherableIfaces(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetheredIfaces} as alternative") String[] getTetheredIfaces(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetheringErroredIfaces} " + + "as Alternative") String[] getTetheringErroredIfaces(); - String[] getTetheredDhcpRanges(); - - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableUsbRegexs} as alternative") String[] getTetherableUsbRegexs(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableWifiRegexs} as alternative") String[] getTetherableWifiRegexs(); - String[] getTetherableBluetoothRegexs(); - - int setUsbTethering(boolean enable, String callerPkg); - @UnsupportedAppUsage(maxTargetSdk = 28) void reportInetCondition(int networkType, int percentage); @@ -217,11 +206,5 @@ interface IConnectivityManager boolean isCallerCurrentAlwaysOnVpnApp(); boolean isCallerCurrentAlwaysOnVpnLockdownApp(); - void getLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg); - - void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); - void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); - IBinder startOrGetTestNetworkService(); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7629e1b57a4d..462627e08520 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9563,35 +9563,37 @@ public final class Settings { */ public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule"; - /** - * Used to select TCP's default initial receiver window size in segments - defaults to a build config value - * @hide - */ - public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd"; + /** + * Used to select TCP's default initial receiver window size in segments - defaults to a + * build config value. + * @hide + */ + public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd"; - /** - * Used to disable Tethering on a device - defaults to true - * @hide - */ - public static final String TETHER_SUPPORTED = "tether_supported"; + /** + * Used to disable Tethering on a device - defaults to true. + * @hide + */ + @SystemApi + public static final String TETHER_SUPPORTED = "tether_supported"; - /** - * Used to require DUN APN on the device or not - defaults to a build config value - * which defaults to false - * @hide - */ - public static final String TETHER_DUN_REQUIRED = "tether_dun_required"; + /** + * Used to require DUN APN on the device or not - defaults to a build config value + * which defaults to false. + * @hide + */ + public static final String TETHER_DUN_REQUIRED = "tether_dun_required"; - /** - * Used to hold a gservices-provisioned apn value for DUN. If set, or the - * corresponding build config values are set it will override the APN DB - * values. - * Consists of a comma seperated list of strings: - * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" - * note that empty fields can be omitted: "name,apn,,,,,,,,,310,260,,DUN" - * @hide - */ - public static final String TETHER_DUN_APN = "tether_dun_apn"; + /** + * Used to hold a gservices-provisioned apn value for DUN. If set, or the + * corresponding build config values are set it will override the APN DB + * values. + * Consists of a comma separated list of strings: + * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" + * note that empty fields can be omitted: "name,apn,,,,,,,,,310,260,,DUN" + * @hide + */ + public static final String TETHER_DUN_APN = "tether_dun_apn"; /** * Used to disable trying to talk to any available tethering offload HAL. diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml index 07a5617009d5..39973715a47d 100644 --- a/data/etc/hiddenapi-package-whitelist.xml +++ b/data/etc/hiddenapi-package-whitelist.xml @@ -65,4 +65,7 @@ Do NOT include any apps that are updatable via Play Store! <hidden-api-whitelisted-app package="com.android.terminal" /> <hidden-api-whitelisted-app package="com.android.wallpaper" /> <hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" /> + <!-- STOPSHIP: Remove this when fixing all @hide usage for tethering.--> + <hidden-api-whitelisted-app package="com.android.networkstack.tethering" /> + <hidden-api-whitelisted-app package="com.android.networkstack" /> </config> diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 3c953b348ed9..08552cbfd394 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -29,9 +29,11 @@ java_defaults { "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.control-V1.0-java", - "tethering-client", ], - libs: ["unsupportedappusage"], + libs: [ + "framework-tethering", + ], + manifest: "AndroidManifestBase.xml", } @@ -90,6 +92,10 @@ java_defaults { resource_dirs: [ "res", ], + libs: [ + "framework-tethering", + ], + jarjar_rules: "jarjar-rules.txt", optimize: { proguard_flags_files: ["proguard.flags"], }, @@ -104,7 +110,6 @@ android_app { manifest: "AndroidManifest_InProcess.xml", // InProcessTethering is a replacement for Tethering overrides: ["Tethering"], - // TODO: use PlatformNetworkPermissionConfig. } // Updatable tethering packaged as an application diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index 8ba05df99e96..87a8c3f5c68a 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -21,6 +21,21 @@ android:sharedUserId="android.uid.networkstack"> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> + <!-- Permissions must be defined here, and not in the base manifest, as the tethering + running in the system server process does not need any permission, and having + privileged permissions added would cause crashes on startup unless they are also + added to the privileged permissions whitelist for that package. --> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <uses-permission android:name="android.permission.BROADCAST_STICKY" /> + <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> + <uses-permission android:name="android.permission.MANAGE_USB" /> + <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> + <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> + <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.WRITE_SETTINGS" /> + <application android:process="com.android.networkstack.process" android:extractNativeLibs="false" diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml index 029b6c3313a7..02ea551254b9 100644 --- a/packages/Tethering/AndroidManifest_InProcess.xml +++ b/packages/Tethering/AndroidManifest_InProcess.xml @@ -22,11 +22,9 @@ 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"> + android:permission="android.permission.MAINLINE_NETWORK_STACK"> <intent-filter> <action android:name="android.net.ITetheringConnector.InProcess"/> </intent-filter> diff --git a/packages/Tethering/CleanSpec.mk b/packages/Tethering/CleanSpec.mk index 70db351a6928..30bdd581d0af 100644 --- a/packages/Tethering/CleanSpec.mk +++ b/packages/Tethering/CleanSpec.mk @@ -46,6 +46,12 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Tethering) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/InProcessTethering) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/InProcessTethering*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/InProcessTethering*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system_other/system/priv-app/InProcessTethering) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.tethering) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex/com.android.tethering.apex) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/com.android.tethering*) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp index af6af93650af..94ef11cc127a 100644 --- a/packages/Tethering/apex/Android.bp +++ b/packages/Tethering/apex/Android.bp @@ -16,6 +16,7 @@ apex { name: "com.android.tethering", + java_libs: ["framework-tethering"], apps: ["Tethering"], manifest: "manifest.json", key: "com.android.tethering.key", diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index adc5a723a960..5785707cb9c5 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -12,7 +12,6 @@ // 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. -// // AIDL interfaces between the core system and the tethering mainline module. aidl_interface { @@ -20,10 +19,7 @@ aidl_interface { 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", + "src/android/net/*.aidl", ], backend: { ndk: { @@ -36,16 +32,32 @@ aidl_interface { } java_library { - name: "tethering-client", + name: "framework-tethering", sdk_version: "system_current", + srcs: [ + "src/android/net/TetheringManager.java", + ":framework-tethering-annotations", + ], static_libs: [ "tethering-aidl-interfaces-java", ], + jarjar_rules: "jarjar-rules.txt", + installable: true, + + libs: [ + "android_system_stubs_current", + ], } -// 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"], + name: "framework-tethering-srcs", + srcs: [ + "src/android/net/TetheringManager.java", + "src/android/net/IIntResultListener.aidl", + "src/android/net/ITetheringEventCallback.aidl", + "src/android/net/ITetheringConnector.aidl", + "src/android/net/TetheringConfigurationParcel.aidl", + "src/android/net/TetherStatesParcel.aidl", + ], + path: "src" } diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt new file mode 100644 index 000000000000..35e0f88e70fa --- /dev/null +++ b/packages/Tethering/common/TetheringLib/jarjar-rules.txt @@ -0,0 +1 @@ +rule android.annotation.** com.android.networkstack.tethering.annotation.@1 diff --git a/core/java/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/IIntResultListener.aidl index d502088542a6..c3d66ee14526 100644 --- a/core/java/android/net/ITetheringEventCallback.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/IIntResultListener.aidl @@ -16,13 +16,10 @@ package android.net; -import android.net.Network; - /** - * Callback class for receiving tethering changed events - * @hide + * Listener interface allowing objects to listen to various module event. + * {@hide} */ -oneway interface ITetheringEventCallback -{ - void onUpstreamChanged(in Network network); +oneway interface IIntResultListener { + void onResult(int resultCode); } diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index bfe502fbeb11..d30c39986984 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -15,23 +15,31 @@ */ package android.net; -import android.net.ITetherInternalCallback; +import android.net.IIntResultListener; +import android.net.ITetheringEventCallback; import android.os.ResultReceiver; /** @hide */ oneway interface ITetheringConnector { - void tether(String iface); + void tether(String iface, String callerPkg, IIntResultListener receiver); - void untether(String iface); + void untether(String iface, String callerPkg, IIntResultListener receiver); - void setUsbTethering(boolean enable); + void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver); - void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi); + void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi, + String callerPkg); - void stopTethering(int type); + void stopTethering(int type, String callerPkg, IIntResultListener receiver); void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, - boolean showEntitlementUi); + boolean showEntitlementUi, String callerPkg); - void registerTetherInternalCallback(ITetherInternalCallback callback); + void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); + + void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); + + void isTetheringSupported(String callerPkg, IIntResultListener receiver); + + void stopAllTethering(String callerPkg, IIntResultListener receiver); } diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl index abb00e819f50..28361954e11e 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl +++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl @@ -21,14 +21,15 @@ import android.net.TetheringConfigurationParcel; import android.net.TetherStatesParcel; /** - * Callback class for receiving tethering changed events + * Callback class for receiving tethering changed events. * @hide */ -oneway interface ITetherInternalCallback +oneway interface ITetheringEventCallback { + void onCallbackStarted(in Network network, in TetheringConfigurationParcel config, + in TetherStatesParcel states); + void onCallbackStopped(int errorCode); 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/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 7fb286b5fa11..a49ab85d2faf 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -15,147 +15,155 @@ */ package android.net; -import static android.Manifest.permission.NETWORK_STACK; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.util.SharedLog; +import android.content.Context; +import android.net.ConnectivityManager.OnTetheringEventCallback; 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 android.util.ArrayMap; +import android.util.Log; -import com.android.internal.annotations.GuardedBy; - -import java.io.PrintWriter; -import java.util.StringJoiner; +import java.util.concurrent.Executor; /** - * Service used to communicate with the tethering, which is running in a separate module. + * This class provides the APIs to control the tethering service. + * <p> The primary responsibilities of this class are to provide the APIs for applications to + * start tethering, stop tethering, query configuration and query status. + * * @hide */ +// TODO: make it @SystemApi public class TetheringManager { private static final String TAG = TetheringManager.class.getSimpleName(); + private static final int DEFAULT_TIMEOUT_MS = 60_000; private static TetheringManager sInstance; - @Nullable - private ITetheringConnector mConnector; - private TetherInternalCallback mCallback; - private Network mTetherUpstream; + private final ITetheringConnector mConnector; + private final TetheringCallbackInternal mCallback; + private final Context mContext; + private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback> + mTetheringEventCallbacks = new ArrayMap<>(); + private TetheringConfigurationParcel mTetheringConfiguration; private TetherStatesParcel mTetherStatesParcel; - private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks = - new RemoteCallbackList<>(); - @GuardedBy("mLog") - private final SharedLog mLog = new SharedLog(TAG); - - private TetheringManager() { } + public static final int TETHER_ERROR_NO_ERROR = 0; + public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; + public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; + public static final int TETHER_ERROR_UNSUPPORTED = 3; + public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; + public static final int TETHER_ERROR_MASTER_ERROR = 5; + public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; + public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; + public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; + public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; + public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; + public static final int TETHER_ERROR_PROVISION_FAILED = 11; + public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; + public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; + public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; + public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; /** - * Get the TetheringManager singleton instance. + * Create a TetheringManager object for interacting with the tethering service. */ - public static synchronized TetheringManager getInstance() { - if (sInstance == null) { - sInstance = new TetheringManager(); + public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) { + mContext = context; + mConnector = ITetheringConnector.Stub.asInterface(service); + mCallback = new TetheringCallbackInternal(); + + final String pkgName = mContext.getOpPackageName(); + Log.i(TAG, "registerTetheringEventCallback:" + pkgName); + try { + mConnector.registerTetheringEventCallback(mCallback, pkgName); + } catch (RemoteException e) { + throw new IllegalStateException(e); } - return sInstance; } - private class TetheringConnection implements - ConnectivityModuleConnector.ModuleServiceCallback { - @Override - public void onModuleServiceConnected(@NonNull IBinder service) { - logi("Tethering service connected"); - registerTetheringService(service); - } + private interface RequestHelper { + void runRequest(IIntResultListener listener); } - private void registerTetheringService(@NonNull IBinder service) { - final ITetheringConnector connector = ITetheringConnector.Stub.asInterface(service); + private class RequestDispatcher { + private final ConditionVariable mWaiting; + public int mRemoteResult; - log("Tethering service registered"); + private final IIntResultListener mListener = new IIntResultListener.Stub() { + @Override + public void onResult(final int resultCode) { + mRemoteResult = resultCode; + mWaiting.open(); + } + }; - // 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(); + RequestDispatcher() { + mWaiting = new ConditionVariable(); } - } - private class TetherInternalCallback extends ITetherInternalCallback.Stub { - private final ConditionVariable mWaitForCallback = new ConditionVariable(false); - private static final int EVENT_CALLBACK_TIMEOUT_MS = 60_000; + int waitForResult(final RequestHelper request) { + request.runRequest(mListener); + if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) { + throw new IllegalStateException("Callback timeout"); + } - @Override - public void onUpstreamChanged(Network network) { - mTetherUpstream = network; - reportUpstreamChanged(network); - } + throwIfPermissionFailure(mRemoteResult); - @Override - public void onConfigurationChanged(TetheringConfigurationParcel config) { - mTetheringConfiguration = config; + return mRemoteResult; } + } - @Override - public void onTetherStatesChanged(TetherStatesParcel states) { - mTetherStatesParcel = states; + private void throwIfPermissionFailure(final int errorCode) { + switch (errorCode) { + case TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION: + throw new SecurityException("No android.permission.TETHER_PRIVILEGED" + + " or android.permission.WRITE_SETTINGS permission"); + case TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION: + throw new SecurityException( + "No android.permission.ACCESS_NETWORK_STATE permission"); } + } + + private class TetheringCallbackInternal extends ITetheringEventCallback.Stub { + private int mError = TETHER_ERROR_NO_ERROR; + private final ConditionVariable mWaitForCallback = new ConditionVariable(); @Override - public void onCallbackCreated(Network network, TetheringConfigurationParcel config, + public void onCallbackStarted(Network network, TetheringConfigurationParcel config, TetherStatesParcel states) { - mTetherUpstream = network; mTetheringConfiguration = config; mTetherStatesParcel = states; mWaitForCallback.open(); } - boolean awaitCallbackCreation() { - return mWaitForCallback.block(EVENT_CALLBACK_TIMEOUT_MS); + @Override + public void onCallbackStopped(int errorCode) { + mError = errorCode; + mWaitForCallback.open(); } - } - 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(); + @Override + public void onUpstreamChanged(Network network) { } + + @Override + public void onConfigurationChanged(TetheringConfigurationParcel config) { + mTetheringConfiguration = config; } - } - /** - * 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"); + @Override + public void onTetherStatesChanged(TetherStatesParcel states) { + mTetherStatesParcel = states; + } + + public void waitForStarted() { + mWaitForCallback.block(DEFAULT_TIMEOUT_MS); + throwIfPermissionFailure(mError); + } } /** @@ -165,108 +173,110 @@ public class TetheringManager { * 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(). + * active. * - * @deprecated The only usages should be in PanService and Wifi P2P which - * need direct access. + * @deprecated The only usages is PanService. It uses this for legacy reasons + * and will migrate away as soon as possible. * - * {@hide} + * @param iface the interface name to tether. + * @return error a {@code TETHER_ERROR} value indicating success or failure type */ @Deprecated - public int tether(@NonNull String iface) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return TETHER_ERROR_SERVICE_UNAVAIL; - } - try { - mConnector.tether(iface); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return TETHER_ERROR_NO_ERROR; + public int tether(@NonNull final String iface) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "tether caller:" + callerPkg); + final RequestDispatcher dispatcher = new RequestDispatcher(); + + return dispatcher.waitForResult(listener -> { + try { + mConnector.tether(iface, callerPkg, listener); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + }); } /** * Stop tethering the named interface. * - * @deprecated - * {@hide} + * @deprecated The only usages is PanService. It uses this for legacy reasons + * and will migrate away as soon as possible. */ @Deprecated - public int untether(@NonNull String iface) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return TETHER_ERROR_SERVICE_UNAVAIL; - } - try { - mConnector.untether(iface); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return TETHER_ERROR_NO_ERROR; + public int untether(@NonNull final String iface) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "untether caller:" + callerPkg); + + final RequestDispatcher dispatcher = new RequestDispatcher(); + + return dispatcher.waitForResult(listener -> { + try { + mConnector.untether(iface, callerPkg, listener); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + }); } /** - * 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. + * Attempt to both alter the mode of USB and Tethering of USB. * - * @deprecated - * {@hide} + * @deprecated 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 - public int setUsbTethering(boolean enable) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return TETHER_ERROR_SERVICE_UNAVAIL; - } - try { - mConnector.setUsbTethering(enable); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return TETHER_ERROR_NO_ERROR; + public int setUsbTethering(final boolean enable) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "setUsbTethering caller:" + callerPkg); + + final RequestDispatcher dispatcher = new RequestDispatcher(); + + return dispatcher.waitForResult(listener -> { + try { + mConnector.setUsbTethering(enable, 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. * - * {@hide} */ // TODO: improve the usage of ResultReceiver, b/145096122 - public void startTethering(int type, @NonNull ResultReceiver receiver, - boolean showProvisioningUi) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return; - } + public void startTethering(final int type, @NonNull final ResultReceiver receiver, + final boolean showProvisioningUi) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "startTethering caller:" + callerPkg); + try { - mConnector.startTethering(type, receiver, showProvisioningUi); + mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw new IllegalStateException(e); } } /** * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if * applicable. - * - * {@hide} */ - public void stopTethering(int type) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return; - } - try { - mConnector.stopTethering(type); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + public void stopTethering(final int type) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "stopTethering caller:" + callerPkg); + + final RequestDispatcher dispatcher = new RequestDispatcher(); + + dispatcher.waitForResult(listener -> { + try { + mConnector.stopTethering(type, callerPkg, listener); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + }); } /** @@ -277,47 +287,109 @@ public class TetheringManager { * if it's really needed. */ // TODO: improve the usage of ResultReceiver, b/145096122 - public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver, - boolean showEntitlementUi) { - if (mConnector == null) { - Slog.wtf(TAG, "Tethering not ready yet"); - return; - } + public void requestLatestTetheringEntitlementResult(final int type, + @NonNull final ResultReceiver receiver, final boolean showEntitlementUi) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg); + try { - mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi, + callerPkg); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw new IllegalStateException(e); } } /** - * Register tethering event callback. + * Start listening to tethering change events. Any new added callback will receive the last + * tethering status right away. If callback is registered, + * {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering + * has no upstream or disabled, the argument of callback will be null. The same callback object + * cannot be registered twice. * - * {@hide} + * @param executor the executor on which callback will be invoked. + * @param callback the callback to be called when tethering has change events. */ - public void registerTetheringEventCallback(@NonNull ITetheringEventCallback callback) { - mTetheringEventCallbacks.register(callback); + public void registerTetheringEventCallback(@NonNull Executor executor, + @NonNull OnTetheringEventCallback callback) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg); + + synchronized (mTetheringEventCallbacks) { + if (!mTetheringEventCallbacks.containsKey(callback)) { + throw new IllegalArgumentException("callback was already registered."); + } + final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() { + @Override + public void onUpstreamChanged(Network network) throws RemoteException { + executor.execute(() -> { + callback.onUpstreamChanged(network); + }); + } + + @Override + public void onCallbackStarted(Network network, TetheringConfigurationParcel config, + TetherStatesParcel states) { + executor.execute(() -> { + callback.onUpstreamChanged(network); + }); + } + + @Override + public void onCallbackStopped(int errorCode) { + executor.execute(() -> { + throwIfPermissionFailure(errorCode); + }); + } + + @Override + public void onConfigurationChanged(TetheringConfigurationParcel config) { } + + @Override + public void onTetherStatesChanged(TetherStatesParcel states) { } + }; + try { + mConnector.registerTetheringEventCallback(remoteCallback, callerPkg); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + mTetheringEventCallbacks.put(callback, remoteCallback); + } } /** - * Unregister tethering event callback. + * Remove tethering event callback previously registered with + * {@link #registerTetheringEventCallback}. * - * {@hide} + * @param callback previously registered callback. */ - public void unregisterTetheringEventCallback(@NonNull ITetheringEventCallback callback) { - mTetheringEventCallbacks.unregister(callback); + public void unregisterTetheringEventCallback(@NonNull final OnTetheringEventCallback callback) { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg); + + synchronized (mTetheringEventCallbacks) { + ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback); + if (remoteCallback == null) { + throw new IllegalArgumentException("callback was not registered."); + } + try { + mConnector.unregisterTetheringEventCallback(remoteCallback, callerPkg); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } } /** * Get a more detailed error code after a Tethering or Untethering * request asynchronously failed. * - * {@hide} + * @param iface The name of the interface of interest + * @return error The error code of the last error tethering or untethering the named + * interface */ - public int getLastTetherError(@NonNull String iface) { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + public int getLastTetherError(@NonNull final String iface) { + mCallback.waitForStarted(); if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR; int i = 0; @@ -334,12 +406,11 @@ public class TetheringManager { * USB network interfaces. If USB tethering is not supported by the * device, this list should be empty. * - * {@hide} + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable usb interfaces. */ public @NonNull String[] getTetherableUsbRegexs() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); return mTetheringConfiguration.tetherableUsbRegexs; } @@ -348,12 +419,11 @@ public class TetheringManager { * Wifi network interfaces. If Wifi tethering is not supported by the * device, this list should be empty. * - * {@hide} + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable wifi interfaces. */ public @NonNull String[] getTetherableWifiRegexs() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); return mTetheringConfiguration.tetherableWifiRegexs; } @@ -362,12 +432,11 @@ public class TetheringManager { * Bluetooth network interfaces. If Bluetooth tethering is not supported by the * device, this list should be empty. * - * {@hide} + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable bluetooth interfaces. */ public @NonNull String[] getTetherableBluetoothRegexs() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); return mTetheringConfiguration.tetherableBluetoothRegexs; } @@ -375,40 +444,42 @@ public class TetheringManager { * Get the set of tetherable, available interfaces. This list is limited by * device configuration and current interface existence. * - * {@hide} + * @return an array of 0 or more Strings of tetherable interface names. */ public @NonNull String[] getTetherableIfaces() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.availableList; } /** * Get the set of tethered interfaces. * - * {@hide} + * @return an array of 0 or more String of currently tethered interface names. */ public @NonNull String[] getTetheredIfaces() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.tetheredList; } /** * Get the set of interface names which attempted to tether but - * failed. + * failed. Re-attempting to tether may cause them to reset to the Tethered + * state. Alternatively, causing the interface to be destroyed and recreated + * may cause them to reset to the available state. + * {@link ConnectivityManager#getLastTetherError} can be used to get more + * information on the cause of the errors. * - * {@hide} + * @return an array of 0 or more String indicating the interface names + * which failed to tether. */ public @NonNull String[] getTetheringErroredIfaces() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); if (mTetherStatesParcel == null) return new String[0]; + return mTetherStatesParcel.erroredIfaceList; } @@ -416,123 +487,49 @@ public class TetheringManager { * Get the set of tethered dhcp ranges. * * @deprecated This API just return the default value which is not used in DhcpServer. - * {@hide} */ @Deprecated public @NonNull String[] getTetheredDhcpRanges() { - if (!mCallback.awaitCallbackCreation()) { - throw new NullPointerException("callback was not ready yet"); - } + mCallback.waitForStarted(); return mTetheringConfiguration.legacyDhcpRanges; } /** - * Check if the device allows for tethering. + * Check if the device allows for tethering. It may be disabled via + * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or + * due to device configuration. * - * {@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. + * @return a boolean - {@code true} indicating Tethering is supported. */ - private void logWtf(@NonNull String message, @Nullable Throwable e) { - Slog.wtf(TAG, message); - synchronized (mLog) { - mLog.e(message, e); - } - } + public boolean isTetheringSupported() { + final String callerPkg = mContext.getOpPackageName(); + + final RequestDispatcher dispatcher = new RequestDispatcher(); + final int ret = dispatcher.waitForResult(listener -> { + try { + mConnector.isTetheringSupported(callerPkg, listener); + } catch (RemoteException e) { + throw new IllegalStateException(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); - } + return ret == TETHER_ERROR_NO_ERROR; } /** - * Log a INFO level message in the local and system logs. + * Stop all active tethering. */ - 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(); + public void stopAllTethering() { + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "stopAllTethering caller:" + callerPkg); + + final RequestDispatcher dispatcher = new RequestDispatcher(); + dispatcher.waitForResult(listener -> { + try { + mConnector.stopAllTethering(callerPkg, listener); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + }); } } diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt new file mode 100644 index 000000000000..dd9eab74e851 --- /dev/null +++ b/packages/Tethering/jarjar-rules.txt @@ -0,0 +1,15 @@ +# These must be kept in sync with the framework-tethering-shared-srcs filegroup. +# If there are files in that filegroup that do not appear here, the classes in the +# module will be overwritten by the ones in the framework. +# Don't jar-jar the entire package because tethering still use some internal classes +# (like TrafficStatsConstants in com.android.internal.util) +# TODO: simply these when tethering is built as system_current. +rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1 +rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 +rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 +rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 +rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 +rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 +rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 + +rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags index 77fc024a8755..1f83a663827c 100644 --- a/packages/Tethering/proguard.flags +++ b/packages/Tethering/proguard.flags @@ -1 +1,9 @@ -#TBD +# Keep class's integer static field for MessageUtils to parsing their name. +-keep class com.android.server.connectivity.tethering.Tethering$TetherMasterSM { + static final int CMD_*; + static final int EVENT_*; +} + +-keepclassmembers class android.net.ip.IpServer { + static final int CMD_*; +} diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index ff3d7bc6fd35..8fde52040ecc 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -30,7 +30,6 @@ import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.NetworkStackClient; import android.net.RouteInfo; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -122,7 +121,7 @@ public class IpServer extends StateMachine { * @param state one of STATE_* * @param lastError one of ConnectivityManager.TETHER_ERROR_* */ - public void updateInterfaceState(IpServer who, int state, int lastError) {} + public void updateInterfaceState(IpServer who, int state, int lastError) { } /** * Notify that |who| has new LinkProperties. @@ -130,11 +129,11 @@ public class IpServer extends StateMachine { * @param who the calling instance of IpServer * @param newLp the new LinkProperties to report */ - public void updateLinkProperties(IpServer who, LinkProperties newLp) {} + public void updateLinkProperties(IpServer who, LinkProperties newLp) { } } /** Capture IpServer dependencies, for injection. */ - public static class Dependencies { + public abstract static class Dependencies { /** Create a RouterAdvertisementDaemon instance to be used by IpServer.*/ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { return new RouterAdvertisementDaemon(ifParams); @@ -149,13 +148,9 @@ public class IpServer extends StateMachine { return NetdService.getInstance(); } - /** - * Create a DhcpServer instance to be used by IpServer. - */ - public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, - DhcpServerCallbacks cb) { - NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb); - } + /** Create a DhcpServer instance to be used by IpServer. */ + public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb); } private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; 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 c4b360d929eb..a68b9b261e59 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -16,6 +16,7 @@ package com.android.server.connectivity.tethering; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; @@ -63,7 +64,7 @@ import android.hardware.usb.UsbManager; import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.ITetherInternalCallback; +import android.net.ITetheringEventCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -89,6 +90,7 @@ 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; @@ -103,7 +105,6 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; -import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.Protocol; @@ -162,6 +163,8 @@ public class Tethering { } private final SharedLog mLog = new SharedLog(TAG); + private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks = + new RemoteCallbackList<>(); // used to synchronize public access to members private final Object mPublicSync; @@ -188,8 +191,8 @@ public class Tethering { 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; + // All the usage of mTetheringEventCallback should run in the same thread. + private ITetheringEventCallback mTetheringEventCallback = null; private volatile TetheringConfiguration mConfig; private InterfaceSet mCurrentUpstreamIfaceSet; @@ -573,6 +576,11 @@ public class Tethering { } } + boolean isTetherProvisioningRequired() { + final TetheringConfiguration cfg = mConfig; + return mEntitlementMgr.isTetherProvisioningRequired(cfg); + } + // TODO: Figure out how to update for local hotspot mode interfaces. private void sendTetherStateChangedBroadcast() { if (!mDeps.isTetheringSupported()) return; @@ -588,7 +596,7 @@ public class Tethering { boolean bluetoothTethered = false; final TetheringConfiguration cfg = mConfig; - final TetherStatesParcel mTetherStatesParcel = new TetherStatesParcel(); + mTetherStatesParcel = new TetherStatesParcel(); synchronized (mPublicSync) { for (int i = 0; i < mTetherStates.size(); i++) { @@ -1796,47 +1804,67 @@ public class Tethering { } /** Register tethering event callback */ - void registerTetherInternalCallback(ITetherInternalCallback callback) { + void registerTetheringEventCallback(ITetheringEventCallback callback) { mHandler.post(() -> { - mTetherInternalCallback = callback; + mTetheringEventCallbacks.register(callback); try { - mTetherInternalCallback.onCallbackCreated(mTetherUpstream, - mConfig.toStableParcelable(), mTetherStatesParcel); + callback.onCallbackStarted(mTetherUpstream, mConfig.toStableParcelable(), + mTetherStatesParcel); } catch (RemoteException e) { // Not really very much to do here. } }); } - 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; + /** Unregister tethering event callback */ + void unregisterTetheringEventCallback(ITetheringEventCallback callback) { + mHandler.post(() -> { + mTetheringEventCallbacks.unregister(callback); + }); + } + private void reportUpstreamChanged(Network network) { + final int length = mTetheringEventCallbacks.beginBroadcast(); try { - mTetherInternalCallback.onUpstreamChanged(network); - } catch (RemoteException e) { - // Not really very much to do here. + 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(); } } private void reportConfigurationChanged(TetheringConfigurationParcel config) { - if (mTetherInternalCallback == null) return; - + final int length = mTetheringEventCallbacks.beginBroadcast(); try { - mTetherInternalCallback.onConfigurationChanged(config); - } catch (RemoteException e) { - // Not really very much to do here. + for (int i = 0; i < length; i++) { + try { + mTetheringEventCallbacks.getBroadcastItem(i).onConfigurationChanged(config); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + } finally { + mTetheringEventCallbacks.finishBroadcast(); } } private void reportTetherStateChanged(TetherStatesParcel states) { - if (mTetherInternalCallback == null) return; - + final int length = mTetheringEventCallbacks.beginBroadcast(); try { - mTetherInternalCallback.onTetherStatesChanged(states); - } catch (RemoteException e) { - // Not really very much to do here. + for (int i = 0; i < length; i++) { + try { + mTetheringEventCallbacks.getBroadcastItem(i).onTetherStatesChanged(states); + } catch (RemoteException e) { + // Not really very much to do here. + } + } + } finally { + mTetheringEventCallbacks.finishBroadcast(); } } @@ -1844,7 +1872,11 @@ public class Tethering { // Binder.java closes the resource for us. @SuppressWarnings("resource") final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump."); + return; + } pw.println("Tethering:"); pw.increaseIndent(); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java index 0ba84127d8da..b16b3294a112 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -39,7 +39,7 @@ import java.util.ArrayList; * * @hide */ -public class TetheringDependencies { +public abstract class TetheringDependencies { /** * Get a reference to the offload hardware interface to be used by tethering. */ @@ -66,9 +66,7 @@ public class TetheringDependencies { /** * Get dependencies to be used by IpServer. */ - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies(); - } + public abstract IpServer.Dependencies getIpServerDependencies(); /** * Indicates whether tethering is supported on the device. @@ -80,9 +78,7 @@ public class TetheringDependencies { /** * Get the NetworkRequest that should be fulfilled by the default network. */ - public NetworkRequest getDefaultNetworkRequest() { - return null; - } + public abstract NetworkRequest getDefaultNetworkRequest(); /** * Get a reference to the EntitlementManager to be used by tethering. @@ -138,14 +134,10 @@ public class TetheringDependencies { /** * Get tethering thread looper. */ - public Looper getTetheringLooper() { - return null; - } + public abstract Looper getTetheringLooper(); /** * Get Context of TetheringSerice. */ - public Context getContext() { - return null; - } + public abstract Context getContext(); } 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 456f2f7f27f5..ba30845e6348 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -16,20 +16,36 @@ package com.android.server.connectivity.tethering; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; + import android.app.Service; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; -import android.net.ITetherInternalCallback; +import android.net.IIntResultListener; +import android.net.INetworkStackConnector; import android.net.ITetheringConnector; +import android.net.ITetheringEventCallback; import android.net.NetworkRequest; +import android.net.dhcp.DhcpServerCallbacks; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.ip.IpServer; import android.net.util.SharedLog; +import android.os.Binder; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.UserManager; import android.provider.Settings; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -52,6 +68,7 @@ public class TetheringService extends Service { private Context mContext; private TetheringDependencies mDeps; private Tethering mTethering; + private UserManager mUserManager; @Override public void onCreate() { @@ -59,6 +76,7 @@ public class TetheringService extends Service { mDeps = getTetheringDependencies(); mContext = mDeps.getContext(); mTethering = makeTethering(mDeps); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); } /** @@ -74,7 +92,7 @@ public class TetheringService extends Service { */ private synchronized IBinder makeConnector() { if (mConnector == null) { - mConnector = new TetheringConnector(mTethering); + mConnector = new TetheringConnector(mTethering, TetheringService.this); } return mConnector; } @@ -87,55 +105,197 @@ public class TetheringService extends Service { } private static class TetheringConnector extends ITetheringConnector.Stub { - private final Tethering mService; + private final TetheringService mService; + private final Tethering mTethering; - TetheringConnector(Tethering tether) { - mService = tether; + TetheringConnector(Tethering tether, TetheringService service) { + mTethering = tether; + mService = service; } @Override - public void tether(String iface) { - mService.tether(iface); + public void tether(String iface, String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + listener.onResult(mTethering.tether(iface)); + } catch (RemoteException e) { } } @Override - public void untether(String iface) { - mService.untether(iface); + public void untether(String iface, String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + listener.onResult(mTethering.untether(iface)); + } catch (RemoteException e) { } } @Override - public void setUsbTethering(boolean enable) { - mService.setUsbTethering(enable); + public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + listener.onResult(mTethering.setUsbTethering(enable)); + } catch (RemoteException e) { } } @Override - public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { - mService.startTethering(type, receiver, showProvisioningUi); + public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi, + String callerPkg) { + if (checkAndNotifyCommonError(callerPkg, receiver)) return; + + mTethering.startTethering(type, receiver, showProvisioningUi); } @Override - public void stopTethering(int type) { - mService.stopTethering(type); + public void stopTethering(int type, String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + mTethering.stopTethering(type); + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException e) { } } @Override public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, - boolean showEntitlementUi) { - mService.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + boolean showEntitlementUi, String callerPkg) { + if (checkAndNotifyCommonError(callerPkg, receiver)) return; + + mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); + } + + @Override + public void registerTetheringEventCallback(ITetheringEventCallback callback, + String callerPkg) { + try { + if (!mService.hasTetherAccessPermission()) { + callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + return; + } + mTethering.registerTetheringEventCallback(callback); + } catch (RemoteException e) { } + } + + @Override + public void unregisterTetheringEventCallback(ITetheringEventCallback callback, + String callerPkg) { + try { + if (!mService.hasTetherAccessPermission()) { + callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + return; + } + mTethering.unregisterTetheringEventCallback(callback); + } catch (RemoteException e) { } + } + + @Override + public void stopAllTethering(String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + mTethering.untetherAll(); + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException e) { } + } + + @Override + public void isTetheringSupported(String callerPkg, IIntResultListener listener) { + if (checkAndNotifyCommonError(callerPkg, listener)) return; + + try { + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException e) { } } @Override - public void registerTetherInternalCallback(ITetherInternalCallback callback) { - mService.registerTetherInternalCallback(callback); + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, + @Nullable String[] args) { + mTethering.dump(fd, writer, args); + } + + private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) { + try { + if (!mService.hasTetherChangePermission(callerPkg)) { + listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + return true; + } + if (!mService.isTetheringSupported()) { + listener.onResult(TETHER_ERROR_UNSUPPORTED); + return true; + } + } catch (RemoteException e) { + return true; + } + + return false; } + + private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) { + if (!mService.hasTetherChangePermission(callerPkg)) { + receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null); + return true; + } + if (!mService.isTetheringSupported()) { + receiver.send(TETHER_ERROR_UNSUPPORTED, null); + return true; + } + + return false; + } + } - @Override - protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, - @Nullable String[] args) { - mTethering.dump(fd, writer, args); + // if ro.tether.denied = true we default to no tethering + // gservices could set the secure setting to 1 though to enable it on a build where it + // had previously been turned off. + private boolean isTetheringSupported() { + final int defaultVal = + SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; + final boolean tetherEnabledInSettings = tetherSupported + && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); + + return tetherEnabledInSettings && mTethering.hasTetherableConfiguration(); + } + + private boolean hasTetherChangePermission(String callerPkg) { + if (checkCallingOrSelfPermission( + android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { + return true; + } + + if (mTethering.isTetherProvisioningRequired()) return false; + + + int uid = Binder.getCallingUid(); + // If callerPkg's uid is not same as Binder.getCallingUid(), + // checkAndNoteWriteSettingsOperation will return false and the operation will be denied. + if (Settings.checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg, + false /* throwException */)) { + return true; + } + + return false; } + private boolean hasTetherAccessPermission() { + if (checkCallingOrSelfPermission( + android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) { + return true; + } + + if (checkCallingOrSelfPermission( + android.Manifest.permission.ACCESS_NETWORK_STATE) == PERMISSION_GRANTED) { + return true; + } + + return false; + } + + /** * An injection method for testing. */ @@ -159,20 +319,55 @@ public class TetheringService extends Service { @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; + return TetheringService.this.isTetheringSupported(); } @Override public Context getContext() { return TetheringService.this; } + + @Override + public IpServer.Dependencies getIpServerDependencies() { + return new IpServer.Dependencies() { + @Override + public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb) { + try { + final INetworkStackConnector service = getNetworkStackConnector(); + if (service == null) return; + + service.makeDhcpServer(ifName, params, cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + }; + } + + // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring + // networkStackClient. + static final int NETWORKSTACK_TIMEOUT_MS = 60_000; + private INetworkStackConnector getNetworkStackConnector() { + IBinder connector; + try { + final long before = System.currentTimeMillis(); + while ((connector = ServiceManager.getService( + Context.NETWORK_STACK_SERVICE)) == null) { + if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { + Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); + return null; + } + Thread.sleep(200); + } + } catch (InterruptedException e) { + Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); + return null; + } + return INetworkStackConnector.Stub.asInterface(connector); + } }; } - return mDeps; } } diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 5b018df21aaf..81a0548cd718 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -33,10 +33,12 @@ android_test { "android.test.runner", "android.test.base", "android.test.mock", + "framework-tethering", ], jni_libs: [ // For mockito extended "libdexmakerjvmtiagent", "libstaticjvmtiagent", ], + jarjar_rules: "jarjar-rules.txt", } diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt new file mode 100644 index 000000000000..64fdebd92726 --- /dev/null +++ b/packages/Tethering/tests/unit/jarjar-rules.txt @@ -0,0 +1,11 @@ +# Don't jar-jar the entire package because this test use some +# internal classes (like ArrayUtils in com.android.internal.util) +rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1 +rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1 +rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1 +rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1 +rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 +rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 +rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 + +rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 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 cdbc54106ce8..31ed8238b663 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 @@ -72,7 +72,7 @@ import android.hardware.usb.UsbManager; import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.ITetherInternalCallback; +import android.net.ITetheringEventCallback; import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; @@ -81,6 +81,7 @@ import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; @@ -167,6 +168,7 @@ public class TetheringTest { @Mock private IDhcpServer mDhcpServer; @Mock private INetd mNetd; @Mock private UserManager mUserManager; + @Mock private NetworkRequest mNetworkRequest; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -311,6 +313,11 @@ public class TetheringTest { } @Override + public NetworkRequest getDefaultNetworkRequest() { + return mNetworkRequest; + } + + @Override public boolean isTetheringSupported() { mIsTetheringSupportedCalls++; return true; @@ -1039,7 +1046,7 @@ public class TetheringTest { expectedInteractionsWithShowNotification); } - private class TestTetherInternalCallback extends ITetherInternalCallback.Stub { + private class TestTetheringEventCallback extends ITetheringEventCallback.Stub { private final ArrayList<Network> mActualUpstreams = new ArrayList<>(); private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs = new ArrayList<>(); @@ -1100,13 +1107,16 @@ public class TetheringTest { } @Override - public void onCallbackCreated(Network network, TetheringConfigurationParcel config, + public void onCallbackStarted(Network network, TetheringConfigurationParcel config, TetherStatesParcel states) { mActualUpstreams.add(network); mTetheringConfigs.add(config); mTetherStates.add(states); } + @Override + public void onCallbackStopped(int errorCode) { } + public void assertNoUpstreamChangeCallback() { assertTrue(mActualUpstreams.isEmpty()); } @@ -1115,10 +1125,20 @@ public class TetheringTest { assertTrue(mTetheringConfigs.isEmpty()); } + public void assertNoStateChangeCallback() { + assertTrue(mTetherStates.isEmpty()); + } + public void assertStateChangeCallback() { assertFalse(mTetherStates.isEmpty()); } + public void assertNoCallback() { + assertNoUpstreamChangeCallback(); + assertNoConfigChangeCallback(); + assertNoStateChangeCallback(); + } + private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual, @NonNull TetheringConfigurationParcel expect) { assertEquals(actual.subId, expect.subId); @@ -1139,18 +1159,19 @@ public class TetheringTest { } @Test - public void testRegisterTetherInternalCallback() throws Exception { - TestTetherInternalCallback callback = new TestTetherInternalCallback(); + public void testRegisterTetheringEventCallback() throws Exception { + TestTetheringEventCallback callback = new TestTetheringEventCallback(); + TestTetheringEventCallback callback2 = new TestTetheringEventCallback(); // 1. Register one callback before running any tethering. - mTethering.registerTetherInternalCallback(callback); + mTethering.registerTetheringEventCallback(callback); mLooper.dispatchAll(); callback.expectUpstreamChanged(new Network[] {null}); callback.expectConfigurationChanged( mTethering.getTetheringConfiguration().toStableParcelable()); TetherStatesParcel tetherState = callback.pollTetherStatesChanged(); assertEquals(tetherState, null); - // 2. Enable wifi tethering + // 2. Enable wifi tethering. NetworkState upstreamState = buildMobileDualStackUpstreamState(); when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) @@ -1168,14 +1189,26 @@ public class TetheringTest { assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME}); callback.expectUpstreamChanged(upstreamState.network); - // 3. Disable wifi tethering. + // 3. Register second callback. + mTethering.registerTetheringEventCallback(callback2); + mLooper.dispatchAll(); + callback2.expectUpstreamChanged(upstreamState.network); + callback2.expectConfigurationChanged( + mTethering.getTetheringConfiguration().toStableParcelable()); + tetherState = callback2.pollTetherStatesChanged(); + assertEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME}); + + // 4. Unregister first callback and disable wifi tethering + mTethering.unregisterTetheringEventCallback(callback); + mLooper.dispatchAll(); mTethering.stopTethering(TETHERING_WIFI); sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED); mLooper.dispatchAll(); - tetherState = callback.pollTetherStatesChanged(); + tetherState = callback2.pollTetherStatesChanged(); assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME}); mLooper.dispatchAll(); - callback.expectUpstreamChanged(new Network[] {null}); + callback2.expectUpstreamChanged(new Network[] {null}); + callback.assertNoCallback(); } @Test diff --git a/services/Android.bp b/services/Android.bp index cf0c15c67a61..501496d8c19c 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -73,6 +73,7 @@ java_library { libs: [ "android.hidl.manager-V1.0-java", + "framework-tethering" ], plugins: [ diff --git a/services/core/Android.bp b/services/core/Android.bp index b7adfa4a3ff1..5b98f06cea2b 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -96,6 +96,7 @@ java_library_static { "android.hardware.tv.cec-V1.0-java", "app-compat-annotations", "vintf-vibrator-java", + "framework-tethering", ], required: [ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b71943504bf6..bb78aceb3b5f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -77,7 +77,6 @@ import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.ISocketKeepaliveCallback; -import android.net.ITetheringEventCallback; import android.net.InetAddresses; import android.net.IpMemoryStore; import android.net.IpPrefix; @@ -278,8 +277,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private MockableSystemProperties mSystemProperties; - private TetheringManager mTetheringManager; - @VisibleForTesting protected final PermissionMonitor mPermissionMonitor; @@ -867,13 +864,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Get a reference to the TetheringManager. - */ - public TetheringManager getTetheringManager() { - return TetheringManager.getInstance(); - } - - /** * @see ProxyTracker */ public ProxyTracker makeProxyTracker(@NonNull Context context, @@ -1072,8 +1062,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - mTetheringManager = mDeps.getTetheringManager(); - mPermissionMonitor = new PermissionMonitor(mContext, mNetd); // Set up the listener for user state for creating user VPNs. @@ -1887,14 +1875,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } mHandler.sendMessage(mHandler.obtainMessage( EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0)); - - // TODO: relocate this specific callback in Tethering. - if (restrictBackground) { - log("onRestrictBackgroundChanged(true): disabling tethering"); - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_USB); - mTetheringManager.stopTethering(ConnectivityManager.TETHERING_BLUETOOTH); - } } }; @@ -2024,12 +2004,6 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid); } - private void enforceTetherAccessPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_NETWORK_STATE, - "ConnectivityService"); - } - private void enforceControlAlwaysOnVpnPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CONTROL_ALWAYS_ON_VPN, @@ -2463,12 +2437,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mKeepaliveTracker.dump(pw); pw.println(); - pw.println("TetheringManager logs:"); - pw.increaseIndent(); - TetheringManager.getInstance().dump(pw); - pw.decreaseIndent(); - - pw.println(); dumpAvoidBadWifiSettings(pw); pw.println(); @@ -3993,183 +3961,55 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - // javadoc from interface - @Override - public int tether(String iface, String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - if (isTetheringSupported()) { - return mTetheringManager.tether(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // javadoc from interface - @Override - public int untether(String iface, String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - - if (isTetheringSupported()) { - return mTetheringManager.untether(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // javadoc from interface @Override + @Deprecated public int getLastTetherError(String iface) { - enforceTetherAccessPermission(); - - if (isTetheringSupported()) { - return mTetheringManager.getLastTetherError(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // TODO - proper iface API for selection by property, inspection, etc - @Override - public String[] getTetherableUsbRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTetheringManager.getTetherableUsbRegexs(); - } else { - return new String[0]; - } - } - - @Override - public String[] getTetherableWifiRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTetheringManager.getTetherableWifiRegexs(); - } else { - return new String[0]; - } - } - - @Override - public String[] getTetherableBluetoothRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTetheringManager.getTetherableBluetoothRegexs(); - } else { - return new String[0]; - } - } - - @Override - public int setUsbTethering(boolean enable, String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - if (isTetheringSupported()) { - return mTetheringManager.setUsbTethering(enable); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); + return tm.getLastTetherError(iface); } - // TODO - move iface listing, queries, etc to new module - // javadoc from interface @Override + @Deprecated public String[] getTetherableIfaces() { - enforceTetherAccessPermission(); - return mTetheringManager.getTetherableIfaces(); + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); + return tm.getTetherableIfaces(); } @Override + @Deprecated public String[] getTetheredIfaces() { - enforceTetherAccessPermission(); - return mTetheringManager.getTetheredIfaces(); + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); + return tm.getTetheredIfaces(); } - @Override - public String[] getTetheringErroredIfaces() { - enforceTetherAccessPermission(); - return mTetheringManager.getTetheringErroredIfaces(); - } - - @Override - public String[] getTetheredDhcpRanges() { - enforceSettingsPermission(); - return mTetheringManager.getTetheredDhcpRanges(); - } @Override - public boolean isTetheringSupported(String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - return isTetheringSupported(); - } - - // if ro.tether.denied = true we default to no tethering - // gservices could set the secure setting to 1 though to enable it on a build where it - // had previously been turned off. - private boolean isTetheringSupported() { - int defaultVal = encodeBool(!mSystemProperties.get("ro.tether.denied").equals("true")); - boolean tetherSupported = toBool(Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.TETHER_SUPPORTED, defaultVal)); - boolean tetherEnabledInSettings = tetherSupported - && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - - // Elevate to system UID to avoid caller requiring MANAGE_USERS permission. - boolean adminUser = false; - final long token = Binder.clearCallingIdentity(); - try { - adminUser = mUserManager.isAdminUser(); - } finally { - Binder.restoreCallingIdentity(token); - } - - return tetherEnabledInSettings && adminUser - && mTetheringManager.hasTetherableConfiguration(); - } - - @Override - public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi, - String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - if (!isTetheringSupported()) { - receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null); - return; - } - mTetheringManager.startTethering(type, receiver, showProvisioningUi); - } + @Deprecated + public String[] getTetheringErroredIfaces() { + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); - @Override - public void stopTethering(int type, String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTetheringManager.stopTethering(type); + return tm.getTetheringErroredIfaces(); } - /** - * Get 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. - */ @Override - public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver, - boolean showEntitlementUi, String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTetheringManager.requestLatestTetheringEntitlementResult( - type, receiver, showEntitlementUi); - } + @Deprecated + public String[] getTetherableUsbRegexs() { + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); - /** Register tethering event callback. */ - @Override - public void registerTetheringEventCallback(ITetheringEventCallback callback, - String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTetheringManager.registerTetheringEventCallback(callback); + return tm.getTetherableUsbRegexs(); } - /** Unregister tethering event callback. */ @Override - public void unregisterTetheringEventCallback(ITetheringEventCallback callback, - String callerPkg) { - ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); - mTetheringManager.unregisterTetheringEventCallback(callback); + @Deprecated + public String[] getTetherableWifiRegexs() { + final TetheringManager tm = (TetheringManager) mContext.getSystemService( + Context.TETHERING_SERVICE); + return tm.getTetherableWifiRegexs(); } // Called when we lose the default network and have no replacement yet. @@ -7050,14 +6890,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Turn airplane mode off setAirplaneMode(false); - if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { - // Untether - String pkgName = mContext.getOpPackageName(); - for (String tether : getTetheredIfaces()) { - untether(tether, pkgName); - } - } - if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) { // Remove always-on package synchronized (mVpns) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index f05bbe215b78..50ae3761b255 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; @@ -42,8 +43,8 @@ import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityModuleConnector; +import android.net.ITetheringConnector; import android.net.NetworkStackClient; -import android.net.TetheringManager; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -2267,8 +2268,14 @@ public final class SystemServer { t.traceBegin("StartTethering"); try { - // Tethering must start after ConnectivityService and NetworkStack. - TetheringManager.getInstance().start(); + // TODO: hide implementation details, b/146312721. + ConnectivityModuleConnector.getInstance().startModuleService( + ITetheringConnector.class.getName(), + PERMISSION_MAINLINE_NETWORK_STACK, service -> { + ServiceManager.addService(Context.TETHERING_SERVICE, service, + false /* allowIsolated */, + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); + }); } catch (Throwable e) { reportWtf("starting Tethering", e); } diff --git a/services/net/Android.bp b/services/net/Android.bp index 3babb0b0a133..9c7cfc197bba 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -10,14 +10,12 @@ java_library_static { srcs: [ ":net-module-utils-srcs", ":services.net-sources", - ":tethering-manager", ], static_libs: [ "dnsresolver_aidl_interface-V2-java", "netd_aidl_interface-unstable-java", "netlink-client", "networkstack-client", - "tethering-client", ], } @@ -25,8 +23,6 @@ filegroup { name: "services-tethering-shared-srcs", srcs: [ ":framework-annotations", - "java/android/net/ConnectivityModuleConnector.java", - "java/android/net/NetworkStackClient.java", "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", ], 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 25028fb3ca0e..c4801aab5c32 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,7 +32,6 @@ 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 @@ -169,7 +168,6 @@ class ConnectivityServiceIntegrationTest { val deps = spy(ConnectivityService.Dependencies()) doReturn(networkStackClient).`when`(deps).networkStack doReturn(metricsLogger).`when`(deps).metricsLogger - 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 a24426b43059..b2d363e27839 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -164,7 +164,6 @@ 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; @@ -1133,7 +1132,6 @@ public class ConnectivityServiceTest { doReturn(new TestNetIdManager()).when(deps).makeNetIdManager(); doReturn(mNetworkStack).when(deps).getNetworkStack(); doReturn(systemProperties).when(deps).getSystemProperties(); - 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()); |