diff options
author | lucaslin <lucaslin@google.com> | 2019-12-17 23:06:12 +0800 |
---|---|---|
committer | lucaslin <lucaslin@google.com> | 2019-12-17 23:06:12 +0800 |
commit | 9b4dfab51a32d365581a48689b74449cfdbdf646 (patch) | |
tree | 9a19a13ecfbc6d150c7d2ad0b93c84d7fc050d89 | |
parent | 4336b91fb41df54e6dcb855e4b30ab1f30dd3409 (diff) |
Use location mcc to load the resource
Provide a way for OEM to provide their customization when
device doesn't have a sim card inserted.
Bug: 141406258
Test: 1. Build pass
2. atest NetworkStackTests
Change-Id: Iad8340e643580f8efa536884d22f0ea0a97cd9a5
-rw-r--r-- | AndroidManifest.xml | 1 | ||||
-rw-r--r-- | res/values/config.xml | 3 | ||||
-rw-r--r-- | res/values/overlayable.xml | 1 | ||||
-rw-r--r-- | src/com/android/server/connectivity/NetworkMonitor.java | 99 | ||||
-rw-r--r-- | tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java | 52 |
5 files changed, 154 insertions, 2 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9628b3f..b1603d8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -30,6 +30,7 @@ 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.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> diff --git a/res/values/config.xml b/res/values/config.xml index 478ed6b..13ab04e 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -43,4 +43,7 @@ <!-- Customized default DNS Servers address. --> <string-array name="config_default_dns_servers" translatable="false"> </string-array> + <!-- Set to true if NetworkMonitor needs to load the resource by neighbor mcc when device + doesn't have a SIM card inserted. --> + <bool name="config_no_sim_card_uses_neighbor_mcc">false</bool> </resources> diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml index b9d5337..4727215 100644 --- a/res/values/overlayable.xml +++ b/res/values/overlayable.xml @@ -21,6 +21,7 @@ <item type="string" name="config_captive_portal_http_url"/> <item type="string" name="config_captive_portal_https_url"/> <item type="array" name="config_captive_portal_fallback_urls"/> + <item type="bool" name="config_no_sim_card_uses_neighbor_mcc"/> <!-- Configuration value for DhcpResults --> <item type="array" name="config_default_dns_servers"/> </policy> diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java index 3dfe004..2c9ffd6 100644 --- a/src/com/android/server/connectivity/NetworkMonitor.java +++ b/src/com/android/server/connectivity/NetworkMonitor.java @@ -76,6 +76,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DnsResolver; @@ -101,11 +103,19 @@ import android.net.wifi.WifiManager; import android.os.Build; import android.os.Bundle; import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.telephony.AccessNetworkConstants; +import android.telephony.CellIdentityNr; +import android.telephony.CellInfo; +import android.telephony.CellInfoGsm; +import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; +import android.telephony.CellInfoTdscdma; +import android.telephony.CellInfoWcdma; import android.telephony.CellSignalStrength; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; @@ -116,6 +126,7 @@ import android.util.Log; import android.util.Pair; import androidx.annotation.ArrayRes; +import androidx.annotation.BoolRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -141,8 +152,10 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -1315,8 +1328,78 @@ public class NetworkMonitor extends StateMachine { CAPTIVE_PORTAL_USE_HTTPS, 1) == 1; } + @Nullable + private String getMccFromCellInfo(final CellInfo cell) { + if (cell instanceof CellInfoGsm) { + return ((CellInfoGsm) cell).getCellIdentity().getMccString(); + } else if (cell instanceof CellInfoLte) { + return ((CellInfoLte) cell).getCellIdentity().getMccString(); + } else if (cell instanceof CellInfoWcdma) { + return ((CellInfoWcdma) cell).getCellIdentity().getMccString(); + } else if (cell instanceof CellInfoTdscdma) { + return ((CellInfoTdscdma) cell).getCellIdentity().getMccString(); + } else if (cell instanceof CellInfoNr) { + return ((CellIdentityNr) ((CellInfoNr) cell).getCellIdentity()).getMccString(); + } else { + return null; + } + } + + /** + * Return location mcc. + */ + @VisibleForTesting + @Nullable + protected String getLocationMcc() { + // Adding this check is because the new permission won't be granted by mainline update, + // the new permission only be granted by OTA for current design. Tracking: b/145774617. + if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, + Process.myPid(), Process.myUid()) + == PackageManager.PERMISSION_DENIED) { + log("getLocationMcc : NetworkStack does not hold ACCESS_FINE_LOCATION"); + return null; + } + try { + final List<CellInfo> cells = mTelephonyManager.getAllCellInfo(); + final Map<String, Integer> countryCodeMap = new HashMap<>(); + int maxCount = 0; + for (final CellInfo cell : cells) { + final String mcc = getMccFromCellInfo(cell); + if (mcc != null) { + final int count = countryCodeMap.getOrDefault(mcc, 0) + 1; + countryCodeMap.put(mcc, count); + } + } + // Return the MCC which occurs most. + if (countryCodeMap.size() <= 0) return null; + return Collections.max(countryCodeMap.entrySet(), + (e1, e2) -> e1.getValue().compareTo(e2.getValue())).getKey(); + } catch (SecurityException e) { + log("Permission is not granted:" + e); + return null; + } + } + + @VisibleForTesting + protected Context getContextByMccIfNoSimCardOrDefault() { + final boolean useNeighborResource = + getResBooleanConfig(mContext, R.bool.config_no_sim_card_uses_neighbor_mcc); + if (!useNeighborResource + || TelephonyManager.SIM_STATE_READY == mTelephonyManager.getSimState()) { + return mContext; + } + final String mcc = getLocationMcc(); + if (TextUtils.isEmpty(mcc)) { + return mContext; + } + final Configuration config = mContext.getResources().getConfiguration(); + config.mcc = Integer.parseInt(mcc); + return mContext.createConfigurationContext(config); + } + private String getCaptivePortalServerHttpsUrl() { - return getSettingFromResource(mContext, R.string.config_captive_portal_https_url, + final Context targetContext = getContextByMccIfNoSimCardOrDefault(); + return getSettingFromResource(targetContext, R.string.config_captive_portal_https_url, R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL); } @@ -1347,6 +1430,17 @@ public class NetworkMonitor extends StateMachine { } } + @VisibleForTesting + protected boolean getResBooleanConfig(@NonNull final Context context, + @BoolRes int configResource) { + final Resources res = context.getResources(); + try { + return res.getBoolean(configResource); + } catch (Resources.NotFoundException e) { + return false; + } + } + /** * Get the captive portal server HTTP URL that is configured on the device. * @@ -1355,7 +1449,8 @@ public class NetworkMonitor extends StateMachine { * on one URL that can be used, while NetworkMonitor may implement more complex logic. */ public String getCaptivePortalServerHttpUrl() { - return getSettingFromResource(mContext, R.string.config_captive_portal_http_url, + final Context targetContext = getContextByMccIfNoSimCardOrDefault(); + return getSettingFromResource(targetContext, R.string.config_captive_portal_http_url, R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL); } diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java index 75491ec..b72c579 100644 --- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -64,7 +64,10 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DnsResolver; @@ -87,6 +90,11 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; +import android.telephony.CellIdentityGsm; +import android.telephony.CellIdentityLte; +import android.telephony.CellInfo; +import android.telephony.CellInfoGsm; +import android.telephony.CellInfoLte; import android.telephony.CellSignalStrength; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -133,6 +141,7 @@ public class NetworkMonitorTest { private static final String LOCATION_HEADER = "location"; private @Mock Context mContext; + private @Mock Configuration mConfiguration; private @Mock Resources mResources; private @Mock IpConnectivityLog mLogger; private @Mock SharedLog mValidationLogger; @@ -484,6 +493,10 @@ public class NetworkMonitorTest { assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms", mQuitCv.block(HANDLER_TIMEOUT_MS)); } + + protected Context getContext() { + return mContext; + } } private WrappedNetworkMonitor makeMonitor(NetworkCapabilities nc) { @@ -513,6 +526,45 @@ public class NetworkMonitorTest { } @Test + public void testGetLocationMcc() throws Exception { + final WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor(); + doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkPermission( + eq(android.Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt()); + assertNull(wnm.getLocationMcc()); + doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission( + eq(android.Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt()); + doReturn(new ContextWrapper(mContext)).when(mContext).createConfigurationContext(any()); + // Prepare CellInfo and check if the vote mechanism is working or not. + final CellInfoGsm cellInfoGsm1 = new CellInfoGsm(); + final CellInfoGsm cellInfoGsm2 = new CellInfoGsm(); + final CellInfoLte cellInfoLte = new CellInfoLte(); + final CellIdentityGsm cellIdentityGsm = + new CellIdentityGsm(0, 0, 0, 0, "460", "01", "", ""); + final CellIdentityLte cellIdentityLte = + new CellIdentityLte(0, 0, 0, 0, 0, "466", "01", "", ""); + cellInfoGsm1.setCellIdentity(cellIdentityGsm); + cellInfoGsm2.setCellIdentity(cellIdentityGsm); + cellInfoLte.setCellIdentity(cellIdentityLte); + final List<CellInfo> cellList = new ArrayList<CellInfo>(); + cellList.add(cellInfoGsm1); + cellList.add(cellInfoGsm2); + cellList.add(cellInfoLte); + doReturn(cellList).when(mTelephony).getAllCellInfo(); + // The count of 460 is 2 and the count of 466 is 1, so the getLocationMcc() should return + // 460. + assertEquals("460", wnm.getLocationMcc()); + // getContextByMccIfNoSimCardOrDefault() shouldn't return mContext when using neighbor mcc + // is enabled and the sim is not ready. + doReturn(true).when(mResources).getBoolean(R.bool.config_no_sim_card_uses_neighbor_mcc); + doReturn(TelephonyManager.SIM_STATE_ABSENT).when(mTelephony).getSimState(); + doReturn(mConfiguration).when(mResources).getConfiguration(); + assertEquals(460, + wnm.getContextByMccIfNoSimCardOrDefault().getResources().getConfiguration().mcc); + doReturn(false).when(mResources).getBoolean(R.bool.config_no_sim_card_uses_neighbor_mcc); + assertEquals(wnm.getContext(), wnm.getContextByMccIfNoSimCardOrDefault()); + } + + @Test public void testGetIntSetting() throws Exception { WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor(); |