diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index ef2a8e924f..2c6a6748f7 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -18,6 +18,7 @@ package com.android.networkstack.tethering; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; +import static android.content.pm.PackageManager.GET_ACTIVITIES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -70,6 +71,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.EthernetManager; @@ -109,7 +111,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceSpecificException; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -782,11 +783,30 @@ public class Tethering { } } + private boolean isProvisioningNeededButUnavailable() { + return isTetherProvisioningRequired() && !doesEntitlementPackageExist(); + } + boolean isTetherProvisioningRequired() { final TetheringConfiguration cfg = mConfig; return mEntitlementMgr.isTetherProvisioningRequired(cfg); } + private boolean doesEntitlementPackageExist() { + // provisioningApp must contain package and class name. + if (mConfig.provisioningApp.length != 2) { + return false; + } + + final PackageManager pm = mContext.getPackageManager(); + try { + pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + return true; + } + // TODO: Figure out how to update for local hotspot mode interfaces. private void sendTetherStateChangedBroadcast() { if (!isTetheringSupported()) return; @@ -2146,14 +2166,14 @@ public class Tethering { // gservices could set the secure setting to 1 though to enable it on a build where it // had previously been turned off. boolean isTetheringSupported() { - final int defaultVal = - SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + final int defaultVal = mDeps.isTetheringDenied() ? 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 && hasTetherableConfiguration(); + return tetherEnabledInSettings && hasTetherableConfiguration() + && !isProvisioningNeededButUnavailable(); } void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index d637c8646b..31f747d3c4 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -26,6 +26,8 @@ import android.net.util.SharedLog; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.SystemProperties; +import android.text.TextUtils; import androidx.annotation.NonNull; @@ -150,4 +152,11 @@ public abstract class TetheringDependencies { * Get a reference to BluetoothAdapter to be used by tethering. */ public abstract BluetoothAdapter getBluetoothAdapter(); + + /** + * Get SystemProperties which indicate whether tethering is denied. + */ + public boolean isTetheringDenied() { + return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true"); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 9fbb17d968..5302a6bcbd 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -16,6 +16,7 @@ package com.android.networkstack.tethering; +import static android.content.pm.PackageManager.GET_ACTIVITIES; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM; @@ -81,6 +82,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; @@ -204,6 +206,7 @@ public class TetheringTest { @Mock private EthernetManager mEm; @Mock private TetheringNotificationUpdater mNotificationUpdater; @Mock private BpfCoordinator mBpfCoordinator; + @Mock private PackageManager mPackageManager; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -263,6 +266,11 @@ public class TetheringTest { return super.getSystemService(name); } + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + @Override public String getSystemServiceName(Class serviceClass) { if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE; @@ -425,6 +433,11 @@ public class TetheringTest { public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) { return mNotificationUpdater; } + + @Override + public boolean isTetheringDenied() { + return false; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -1951,6 +1964,23 @@ public class TetheringTest { assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_ETH_IFNAME)); } + @Test + public void testProvisioningNeededButUnavailable() throws Exception { + assertTrue(mTethering.isTetheringSupported()); + verify(mPackageManager, never()).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + + setupForRequiredProvisioning(); + assertTrue(mTethering.isTetheringSupported()); + verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + reset(mPackageManager); + + doThrow(PackageManager.NameNotFoundException.class).when(mPackageManager).getPackageInfo( + PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + setupForRequiredProvisioning(); + assertFalse(mTethering.isTetheringSupported()); + verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. }