Replace StringNetworkSpecifier & subId with TelephonyNetworkSpecifer

StringNetworkSpecifier is widely used to specify subscription id for
the NetworkRequest. The raw string field introduce ambiguity and leave
large space for bugs. With TelephonyNetworkSpecifer, we are able to
settle down the type and value of the fields (although currently only
one) and introduce validation to detect the bug in the beginning.

Bug: 145993724
Test: atest FrameworksNetTests FrameworksTelephonyTests &
      make offline-sdk-docs
Change-Id: Iefbad9b1deb3de2c0b262d9ce5ae0704a50d08a6
This commit is contained in:
Rambo Wang
2019-12-12 18:16:10 -08:00
parent 9fef5a5cf0
commit 582ba554de
4 changed files with 125 additions and 23 deletions

View File

@@ -300,23 +300,35 @@ public class NetworkRequest implements Parcelable {
* this without a single transport set will generate an exception, as will
* subsequently adding or removing transports after this is set.
* </p>
* The interpretation of this {@code String} is bearer specific and bearers that use
* it should document their particulars. For example, Bluetooth may use some sort of
* device id while WiFi could used ssid and/or bssid. Cellular may use carrier spn.
* If the {@code networkSpecifier} is provided, it shall be interpreted as follows:
* <ul>
* <li>If the specifier can be parsed as an integer, it will be treated as a
* {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be
* interpreted as a SubscriptionId.
* <li>If the value is an ethernet interface name, it will be treated as such.
* <li>For all other cases, the behavior is undefined.
* </ul>
*
* @param networkSpecifier An {@code String} of opaque format used to specify the bearer
* specific network specifier where the bearer has a choice of
* networks.
* @param networkSpecifier A {@code String} of either a SubscriptionId in cellular
* network request or an ethernet interface name in ethernet
* network request.
*
* @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
*/
@Deprecated
public Builder setNetworkSpecifier(String networkSpecifier) {
/*
* A StringNetworkSpecifier does not accept null or empty ("") strings. When network
* specifiers were strings a null string and an empty string were considered equivalent.
* Hence no meaning is attached to a null or empty ("") string.
*/
try {
int subId = Integer.parseInt(networkSpecifier);
return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(subId).build());
} catch (NumberFormatException nfe) {
// A StringNetworkSpecifier does not accept null or empty ("") strings. When network
// specifiers were strings a null string and an empty string were considered
// equivalent. Hence no meaning is attached to a null or empty ("") string.
return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
: new StringNetworkSpecifier(networkSpecifier));
}
}
/**
* Sets the optional bearer specific network specifier.

View File

@@ -28,7 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.NetworkSpecifier;
import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
@@ -223,14 +223,8 @@ public class NetworkNotificationManager {
// name has been added to it
NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier();
int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
if (specifier instanceof StringNetworkSpecifier) {
try {
subId = Integer.parseInt(
((StringNetworkSpecifier) specifier).specifier);
} catch (NumberFormatException e) {
Slog.e(TAG, "NumberFormatException on "
+ ((StringNetworkSpecifier) specifier).specifier);
}
if (specifier instanceof TelephonyNetworkSpecifier) {
subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
}
details = mTelephonyManager.createForSubscriptionId(subId)

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static org.junit.Assert.assertEquals;
import android.telephony.SubscriptionManager;
import androidx.test.filters.SmallTest;
import org.junit.Test;
/**
* Unit test for {@link android.net.TelephonyNetworkSpecifier}.
*/
@SmallTest
public class TelephonyNetworkSpecifierTest {
private static final int TEST_SUBID = 5;
/**
* Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
* without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
*/
@Test
public void testBuilderBuildWithDefault() {
try {
new TelephonyNetworkSpecifier.Builder().build();
} catch (IllegalArgumentException iae) {
// expected, test pass
}
}
/**
* Validate that no exception will be thrown even if pass invalid subscription id to
* {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
*/
@Test
public void testBuilderBuildWithInvalidSubId() {
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
.build();
assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
/**
* Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
*/
@Test
public void testBuilderBuildWithValidSubId() {
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
assertEquals(TEST_SUBID, specifier.getSubscriptionId());
}
/**
* Validate that parcel marshalling/unmarshalling works.
*/
@Test
public void testParcel() {
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
assertParcelSane(specifier, 1 /* fieldCount */);
}
}

View File

@@ -51,6 +51,7 @@ import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -229,7 +230,7 @@ public class MultipathPolicyTrackerTest {
verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any());
// Simulate callback after capability changes
final NetworkCapabilities capabilities = new NetworkCapabilities()
NetworkCapabilities capabilities = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(TRANSPORT_CELLULAR)
.setNetworkSpecifier(new StringNetworkSpecifier("234"));
@@ -239,6 +240,19 @@ public class MultipathPolicyTrackerTest {
networkCallback.getValue().onCapabilitiesChanged(
TEST_NETWORK,
capabilities);
// make sure it also works with the new introduced TelephonyNetworkSpecifier
capabilities = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(TRANSPORT_CELLULAR)
.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(234).build());
if (!roaming) {
capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
networkCallback.getValue().onCapabilitiesChanged(
TEST_NETWORK,
capabilities);
}
@Test