Loading src/com/android/settings/network/TetherProvisioningActivity.java +11 −11 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; Loading @@ -28,7 +27,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; Loading @@ -37,8 +35,6 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.Utils; /** * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission * restrictions. Specifically, the provisioning apps require Loading @@ -53,7 +49,10 @@ public class TetherProvisioningActivity extends Activity { @VisibleForTesting static final int PROVISION_REQUEST = 0; @VisibleForTesting static final String EXTRA_SUBID = "subId"; static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; @VisibleForTesting public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME = "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME"; @Override public void onCreate(Bundle savedInstanceState) { Loading @@ -62,7 +61,8 @@ public class TetherProvisioningActivity extends Activity { final int tetherType = getIntent().getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); final int tetherSubId = getIntent().getIntExtra( EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); Loading @@ -70,11 +70,11 @@ public class TetherProvisioningActivity extends Activity { finish(); return; } String[] provisionApp = getIntent().getStringArrayExtra(EXTRA_RUN_PROVISION); if (provisionApp == null || provisionApp.length < 2) { final Resources res = Utils.getResourcesForSubId(this, subId); provisionApp = res.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app); String[] provisionApp = getIntent().getStringArrayExtra( EXTRA_TETHER_UI_PROVISIONING_APP_NAME); if (provisionApp == null || provisionApp.length != 2) { Log.e(TAG, "Unexpected provision app configuration"); return; } final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); Loading src/com/android/settings/wifi/tether/TetherService.java +91 −55 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.TetheringManager; import android.os.IBinder; import android.os.ResultReceiver; Loading @@ -52,10 +51,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.Utils; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class TetherService extends Service { private static final String TAG = "TetherService"; Loading @@ -64,7 +62,13 @@ public class TetherService extends Service { @VisibleForTesting public static final String EXTRA_RESULT = "EntitlementResult"; @VisibleForTesting public static final String EXTRA_SUBID = "subId"; public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; @VisibleForTesting public static final String EXTRA_TETHER_PROVISIONING_RESPONSE = "android.net.extra.TETHER_PROVISIONING_RESPONSE"; @VisibleForTesting public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION = "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION"; // Activity results to match the activity provision protocol. // Default to something not ok. Loading @@ -79,6 +83,11 @@ public class TetherService extends Service { private int mCurrentTypeIndex; private boolean mInProvisionCheck; /** Intent action received from the provisioning app when entitlement check completes. */ private String mExpectedProvisionResponseAction = null; /** Intent action sent to the provisioning app to request an entitlement check. */ private String mProvisionAction; private int mSubId = INVALID_SUBSCRIPTION_ID; private TetherServiceWrapper mWrapper; private ArrayList<Integer> mCurrentTethers; private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; Loading @@ -92,10 +101,6 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); registerReceiver(mReceiver, new IntentFilter(provisionResponse), android.Manifest.permission.TETHER_PRIVILEGED, null); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, "")); mCurrentTypeIndex = 0; Loading @@ -106,10 +111,28 @@ public class TetherService extends Service { mPendingCallbacks.put(TETHERING_ETHERNET, new ArrayList<ResultReceiver>()); } // Registers the broadcast receiver for the specified response action, first unregistering // the receiver if it was registered for a different response action. private void maybeRegisterReceiver(final String responseAction) { if (Objects.equals(responseAction, mExpectedProvisionResponseAction)) return; if (mExpectedProvisionResponseAction != null) unregisterReceiver(mReceiver); registerReceiver(mReceiver, new IntentFilter(responseAction), android.Manifest.permission.TETHER_PRIVILEGED, null /* handler */); mExpectedProvisionResponseAction = responseAction; if (DEBUG) Log.d(TAG, "registerReceiver " + responseAction); } private int stopSelfAndStartNotSticky() { stopSelf(); return START_NOT_STICKY; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent.hasExtra(EXTRA_SUBID)) { final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); if (intent.hasExtra(EXTRA_TETHER_SUBID)) { final int tetherSubId = intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); Loading @@ -118,7 +141,9 @@ public class TetherService extends Service { } return START_NOT_STICKY; } mSubId = subId; } if (intent.hasExtra(EXTRA_ADD_TETHER_TYPE)) { int type = intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); ResultReceiver callback = intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK); Loading @@ -128,9 +153,9 @@ public class TetherService extends Service { callbacksForType.add(callback); } else { // Invalid tether type. Just ignore this request and report failure. Log.e(TAG, "Invalid tethering type " + type + ", stopping"); callback.send(TETHER_ERROR_UNKNOWN_IFACE, null); stopSelf(); return START_NOT_STICKY; return stopSelfAndStartNotSticky(); } } Loading @@ -140,6 +165,19 @@ public class TetherService extends Service { } } mProvisionAction = intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION); if (mProvisionAction == null) { Log.e(TAG, "null provisioning action, stop "); return stopSelfAndStartNotSticky(); } final String response = intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE); if (response == null) { Log.e(TAG, "null provisioning response, stop "); return stopSelfAndStartNotSticky(); } maybeRegisterReceiver(response); if (intent.hasExtra(EXTRA_REM_TETHER_TYPE)) { if (!mInProvisionCheck) { int type = intent.getIntExtra(EXTRA_REM_TETHER_TYPE, TETHERING_INVALID); Loading @@ -158,8 +196,7 @@ public class TetherService extends Service { } else if (!mInProvisionCheck) { // If we aren't running any provisioning, no reason to stay alive. if (DEBUG) Log.d(TAG, "Stopping self. startid: " + startId); stopSelf(); return START_NOT_STICKY; return stopSelfAndStartNotSticky(); } // We want to be started if we are killed accidently, so that we can be sure we finish // the check. Loading @@ -175,7 +212,10 @@ public class TetherService extends Service { SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit(); if (mExpectedProvisionResponseAction != null) { unregisterReceiver(mReceiver); mExpectedProvisionResponseAction = null; } if (DEBUG) Log.d(TAG, "Destroying TetherService"); super.onDestroy(); } Loading Loading @@ -220,26 +260,26 @@ public class TetherService extends Service { } private void startProvisioning(int index) { if (index < mCurrentTethers.size()) { if (index >= mCurrentTethers.size()) return; Intent intent = getProvisionBroadcastIntent(index); setEntitlementAppActive(index); if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() if (DEBUG) { Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() + " type: " + mCurrentTethers.get(index)); } sendBroadcast(intent); mInProvisionCheck = true; } } private Intent getProvisionBroadcastIntent(int index) { String provisionAction = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); Intent intent = new Intent(provisionAction); if (mProvisionAction == null) Log.wtf(TAG, "null provisioning action"); Intent intent = new Intent(mProvisionAction); int type = mCurrentTethers.get(index); intent.putExtra(TETHER_CHOICE, type); intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, mSubId); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Loading Loading @@ -282,12 +322,16 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); if (provisionResponse.equals(intent.getAction())) { if (!intent.getAction().equals(mExpectedProvisionResponseAction)) { Log.e(TAG, "Received provisioning response for unexpected action=" + intent.getAction() + ", expected=" + mExpectedProvisionResponseAction); return; } if (!mInProvisionCheck) { Log.e(TAG, "Unexpected provision response " + intent); Log.e(TAG, "Unexpected provisioning response when not in provisioning check" + intent); return; } int checkType = mCurrentTethers.get(mCurrentTypeIndex); Loading @@ -304,7 +348,6 @@ public class TetherService extends Service { startProvisioning(mCurrentTypeIndex); } } } }; @VisibleForTesting Loading @@ -321,8 +364,7 @@ public class TetherService extends Service { /** * A static helper class used for tests. UsageStatsManager cannot be mocked out because * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot * be mocked. This class can be mocked out instead. * it's marked final. This class can be mocked out instead. */ @VisibleForTesting public static class TetherServiceWrapper { Loading @@ -341,10 +383,4 @@ public class TetherService extends Service { return SubscriptionManager.getActiveDataSubscriptionId(); } } @VisibleForTesting Resources getResourceForActiveDataSubId() { final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); return Utils.getResourcesForSubId(this, subId); } } tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java +8 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_WIFI; import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_SUBID; import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; import static com.android.settings.network.TetherProvisioningActivity.PROVISION_REQUEST; import static org.junit.Assert.assertEquals; Loading Loading @@ -72,7 +73,7 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, 10000))) { .putExtra(TetherProvisioningActivity.EXTRA_TETHER_SUBID, 10000))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } Loading @@ -82,12 +83,13 @@ public class TetherProvisioningActivityTest { public void testOnCreate_FinishWithUnavailableProvisioningApp() throws Exception { final WrappedReceiver receiver = new WrappedReceiver(); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); final String[] emptyProvisioningApp = { "", "" }; try (ActivityScenario<TetherProvisioningActivity> scenario = ActivityScenario.launch( new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) .putExtra(EXTRA_RUN_PROVISION, new String[] { "", "" }))) { .putExtra(EXTRA_TETHER_SUBID, subId) .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, emptyProvisioningApp))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } Loading @@ -105,8 +107,8 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) .putExtra(EXTRA_RUN_PROVISION, provisionApp))) { .putExtra(EXTRA_TETHER_SUBID, subId) .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, provisionApp))) { scenario.onActivity(activity -> { assertFalse(activity.isFinishing()); activity.onActivityResult(PROVISION_REQUEST, Activity.RESULT_OK, null /* intent */); Loading tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +10 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,10 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_PROVISIONING_RESPONSE; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SUBID; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; Loading Loading @@ -228,8 +232,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); intent.putExtra(TetherService.EXTRA_SUBID, 1 /* Tested subId number */); intent.putExtra(EXTRA_TETHER_SUBID, 1 /* Tested subId number */); intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); SystemClock.sleep(PROVISION_TIMEOUT); Loading @@ -242,8 +248,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); intent.putExtra(TetherService.EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); intent.putExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); } Loading Loading
src/com/android/settings/network/TetherProvisioningActivity.java +11 −11 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; Loading @@ -28,7 +27,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; Loading @@ -37,8 +35,6 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.Utils; /** * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission * restrictions. Specifically, the provisioning apps require Loading @@ -53,7 +49,10 @@ public class TetherProvisioningActivity extends Activity { @VisibleForTesting static final int PROVISION_REQUEST = 0; @VisibleForTesting static final String EXTRA_SUBID = "subId"; static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; @VisibleForTesting public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME = "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME"; @Override public void onCreate(Bundle savedInstanceState) { Loading @@ -62,7 +61,8 @@ public class TetherProvisioningActivity extends Activity { final int tetherType = getIntent().getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); final int tetherSubId = getIntent().getIntExtra( EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); Loading @@ -70,11 +70,11 @@ public class TetherProvisioningActivity extends Activity { finish(); return; } String[] provisionApp = getIntent().getStringArrayExtra(EXTRA_RUN_PROVISION); if (provisionApp == null || provisionApp.length < 2) { final Resources res = Utils.getResourcesForSubId(this, subId); provisionApp = res.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app); String[] provisionApp = getIntent().getStringArrayExtra( EXTRA_TETHER_UI_PROVISIONING_APP_NAME); if (provisionApp == null || provisionApp.length != 2) { Log.e(TAG, "Unexpected provision app configuration"); return; } final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); Loading
src/com/android/settings/wifi/tether/TetherService.java +91 −55 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.TetheringManager; import android.os.IBinder; import android.os.ResultReceiver; Loading @@ -52,10 +51,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.Utils; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class TetherService extends Service { private static final String TAG = "TetherService"; Loading @@ -64,7 +62,13 @@ public class TetherService extends Service { @VisibleForTesting public static final String EXTRA_RESULT = "EntitlementResult"; @VisibleForTesting public static final String EXTRA_SUBID = "subId"; public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; @VisibleForTesting public static final String EXTRA_TETHER_PROVISIONING_RESPONSE = "android.net.extra.TETHER_PROVISIONING_RESPONSE"; @VisibleForTesting public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION = "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION"; // Activity results to match the activity provision protocol. // Default to something not ok. Loading @@ -79,6 +83,11 @@ public class TetherService extends Service { private int mCurrentTypeIndex; private boolean mInProvisionCheck; /** Intent action received from the provisioning app when entitlement check completes. */ private String mExpectedProvisionResponseAction = null; /** Intent action sent to the provisioning app to request an entitlement check. */ private String mProvisionAction; private int mSubId = INVALID_SUBSCRIPTION_ID; private TetherServiceWrapper mWrapper; private ArrayList<Integer> mCurrentTethers; private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; Loading @@ -92,10 +101,6 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); registerReceiver(mReceiver, new IntentFilter(provisionResponse), android.Manifest.permission.TETHER_PRIVILEGED, null); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, "")); mCurrentTypeIndex = 0; Loading @@ -106,10 +111,28 @@ public class TetherService extends Service { mPendingCallbacks.put(TETHERING_ETHERNET, new ArrayList<ResultReceiver>()); } // Registers the broadcast receiver for the specified response action, first unregistering // the receiver if it was registered for a different response action. private void maybeRegisterReceiver(final String responseAction) { if (Objects.equals(responseAction, mExpectedProvisionResponseAction)) return; if (mExpectedProvisionResponseAction != null) unregisterReceiver(mReceiver); registerReceiver(mReceiver, new IntentFilter(responseAction), android.Manifest.permission.TETHER_PRIVILEGED, null /* handler */); mExpectedProvisionResponseAction = responseAction; if (DEBUG) Log.d(TAG, "registerReceiver " + responseAction); } private int stopSelfAndStartNotSticky() { stopSelf(); return START_NOT_STICKY; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent.hasExtra(EXTRA_SUBID)) { final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); if (intent.hasExtra(EXTRA_TETHER_SUBID)) { final int tetherSubId = intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); Loading @@ -118,7 +141,9 @@ public class TetherService extends Service { } return START_NOT_STICKY; } mSubId = subId; } if (intent.hasExtra(EXTRA_ADD_TETHER_TYPE)) { int type = intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); ResultReceiver callback = intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK); Loading @@ -128,9 +153,9 @@ public class TetherService extends Service { callbacksForType.add(callback); } else { // Invalid tether type. Just ignore this request and report failure. Log.e(TAG, "Invalid tethering type " + type + ", stopping"); callback.send(TETHER_ERROR_UNKNOWN_IFACE, null); stopSelf(); return START_NOT_STICKY; return stopSelfAndStartNotSticky(); } } Loading @@ -140,6 +165,19 @@ public class TetherService extends Service { } } mProvisionAction = intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION); if (mProvisionAction == null) { Log.e(TAG, "null provisioning action, stop "); return stopSelfAndStartNotSticky(); } final String response = intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE); if (response == null) { Log.e(TAG, "null provisioning response, stop "); return stopSelfAndStartNotSticky(); } maybeRegisterReceiver(response); if (intent.hasExtra(EXTRA_REM_TETHER_TYPE)) { if (!mInProvisionCheck) { int type = intent.getIntExtra(EXTRA_REM_TETHER_TYPE, TETHERING_INVALID); Loading @@ -158,8 +196,7 @@ public class TetherService extends Service { } else if (!mInProvisionCheck) { // If we aren't running any provisioning, no reason to stay alive. if (DEBUG) Log.d(TAG, "Stopping self. startid: " + startId); stopSelf(); return START_NOT_STICKY; return stopSelfAndStartNotSticky(); } // We want to be started if we are killed accidently, so that we can be sure we finish // the check. Loading @@ -175,7 +212,10 @@ public class TetherService extends Service { SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit(); if (mExpectedProvisionResponseAction != null) { unregisterReceiver(mReceiver); mExpectedProvisionResponseAction = null; } if (DEBUG) Log.d(TAG, "Destroying TetherService"); super.onDestroy(); } Loading Loading @@ -220,26 +260,26 @@ public class TetherService extends Service { } private void startProvisioning(int index) { if (index < mCurrentTethers.size()) { if (index >= mCurrentTethers.size()) return; Intent intent = getProvisionBroadcastIntent(index); setEntitlementAppActive(index); if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() if (DEBUG) { Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() + " type: " + mCurrentTethers.get(index)); } sendBroadcast(intent); mInProvisionCheck = true; } } private Intent getProvisionBroadcastIntent(int index) { String provisionAction = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); Intent intent = new Intent(provisionAction); if (mProvisionAction == null) Log.wtf(TAG, "null provisioning action"); Intent intent = new Intent(mProvisionAction); int type = mCurrentTethers.get(index); intent.putExtra(TETHER_CHOICE, type); intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, mSubId); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Loading Loading @@ -282,12 +322,16 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); if (provisionResponse.equals(intent.getAction())) { if (!intent.getAction().equals(mExpectedProvisionResponseAction)) { Log.e(TAG, "Received provisioning response for unexpected action=" + intent.getAction() + ", expected=" + mExpectedProvisionResponseAction); return; } if (!mInProvisionCheck) { Log.e(TAG, "Unexpected provision response " + intent); Log.e(TAG, "Unexpected provisioning response when not in provisioning check" + intent); return; } int checkType = mCurrentTethers.get(mCurrentTypeIndex); Loading @@ -304,7 +348,6 @@ public class TetherService extends Service { startProvisioning(mCurrentTypeIndex); } } } }; @VisibleForTesting Loading @@ -321,8 +364,7 @@ public class TetherService extends Service { /** * A static helper class used for tests. UsageStatsManager cannot be mocked out because * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot * be mocked. This class can be mocked out instead. * it's marked final. This class can be mocked out instead. */ @VisibleForTesting public static class TetherServiceWrapper { Loading @@ -341,10 +383,4 @@ public class TetherService extends Service { return SubscriptionManager.getActiveDataSubscriptionId(); } } @VisibleForTesting Resources getResourceForActiveDataSubId() { final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); return Utils.getResourcesForSubId(this, subId); } }
tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java +8 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_WIFI; import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_SUBID; import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; import static com.android.settings.network.TetherProvisioningActivity.PROVISION_REQUEST; import static org.junit.Assert.assertEquals; Loading Loading @@ -72,7 +73,7 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, 10000))) { .putExtra(TetherProvisioningActivity.EXTRA_TETHER_SUBID, 10000))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } Loading @@ -82,12 +83,13 @@ public class TetherProvisioningActivityTest { public void testOnCreate_FinishWithUnavailableProvisioningApp() throws Exception { final WrappedReceiver receiver = new WrappedReceiver(); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); final String[] emptyProvisioningApp = { "", "" }; try (ActivityScenario<TetherProvisioningActivity> scenario = ActivityScenario.launch( new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) .putExtra(EXTRA_RUN_PROVISION, new String[] { "", "" }))) { .putExtra(EXTRA_TETHER_SUBID, subId) .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, emptyProvisioningApp))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } Loading @@ -105,8 +107,8 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) .putExtra(EXTRA_RUN_PROVISION, provisionApp))) { .putExtra(EXTRA_TETHER_SUBID, subId) .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, provisionApp))) { scenario.onActivity(activity -> { assertFalse(activity.isFinishing()); activity.onActivityResult(PROVISION_REQUEST, Activity.RESULT_OK, null /* intent */); Loading
tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +10 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,10 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_PROVISIONING_RESPONSE; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SUBID; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; Loading Loading @@ -228,8 +232,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); intent.putExtra(TetherService.EXTRA_SUBID, 1 /* Tested subId number */); intent.putExtra(EXTRA_TETHER_SUBID, 1 /* Tested subId number */); intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); SystemClock.sleep(PROVISION_TIMEOUT); Loading @@ -242,8 +248,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); intent.putExtra(TetherService.EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); intent.putExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); } Loading