Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aa3a72e authored by Chiachang Wang's avatar Chiachang Wang
Browse files

Monitor system configuration change

The RRO generation does not happen during package installation
and instead after the OMS receives the PACKAGE_ADDED event.
There is a delay where the old idmap is used with the new
target package resulting in a random failure for getting the
overlay in NetworkStack. Given that the fix in OMS and PM may
not be landed in short time, listen the configuration change
to re-query the resource to address this issue as a short
term solution.

Bug: 189738017
Bug: 181919957
Test: atest NetworkStackTests
Change-Id: I9a1ac0a6140fc8e9362324dc99667c7f9fa4c9d5
parent 33756a9b
Loading
Loading
Loading
Loading
+135 −49
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.connectivity;

import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
@@ -392,6 +393,11 @@ public class NetworkMonitor extends StateMachine {
     */
    private static final int CMD_BANDWIDTH_CHECK_TIMEOUT = 24;

    /**
     * Message to self to notify resource configuration is changed.
     */
    private static final int EVENT_RESOURCE_CONFIG_CHANGED = 25;

    // Start mReevaluateDelayMs at this value and double.
    @VisibleForTesting
    static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
@@ -416,7 +422,6 @@ public class NetworkMonitor extends StateMachine {
    private String mPrivateDnsProviderHostname = "";

    private final Context mContext;
    private final Context mCustomizedContext;
    private final INetworkMonitorCallbacks mCallback;
    private final int mCallbackVersion;
    private final Network mCleartextDnsNetwork;
@@ -431,13 +436,21 @@ public class NetworkMonitor extends StateMachine {
    private final TcpSocketTracker mTcpTracker;
    // Configuration values for captive portal detection probes.
    private final String mCaptivePortalUserAgent;
    private final URL[] mCaptivePortalFallbackUrls;
    @NonNull
    private final URL[] mCaptivePortalHttpUrls;
    @NonNull
    private final URL[] mCaptivePortalHttpsUrls;
    // Configuration values in setting providers for captive portal detection probes
    private final String mCaptivePortalHttpsUrlFromSetting;
    private final String mCaptivePortalHttpUrlFromSetting;
    @Nullable
    private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;

    // The probing URLs may be updated after constructor if system notifies configuration changed.
    // Thus, these probing URLs should only be accessed in the StateMachine thread.
    @NonNull
    private URL[] mCaptivePortalFallbackUrls;
    @NonNull
    private URL[] mCaptivePortalHttpUrls;
    @NonNull
    private URL[] mCaptivePortalHttpsUrls;

    // Configuration values for network bandwidth check.
    @Nullable
    private final String mEvaluatingBandwidthUrl;
@@ -511,7 +524,8 @@ public class NetworkMonitor extends StateMachine {
    private @EvaluationType int mDataStallTypeToCollect;
    private boolean mAcceptPartialConnectivity = false;
    private final EvaluationState mEvaluationState = new EvaluationState();

    @NonNull
    private final BroadcastReceiver mConfigurationReceiver;
    private final boolean mPrivateIpNoInternetEnabled;

    private final boolean mMetricsEnabled;
@@ -575,7 +589,6 @@ public class NetworkMonitor extends StateMachine {
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mNotifier = serviceManager.getNotifier();
        mCustomizedContext = getCustomizedContextOrDefault();

        // CHECKSTYLE:OFF IndentationCheck
        addState(mDefaultState);
@@ -590,16 +603,18 @@ public class NetworkMonitor extends StateMachine {
        setInitialState(mDefaultState);
        // CHECKSTYLE:ON IndentationCheck

        mCaptivePortalHttpsUrlFromSetting =
                mDependencies.getSetting(context, CAPTIVE_PORTAL_HTTPS_URL, null);
        mCaptivePortalHttpUrlFromSetting =
                mDependencies.getSetting(context, CAPTIVE_PORTAL_HTTP_URL, null);
        mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
        mPrivateIpNoInternetEnabled = getIsPrivateIpNoInternetEnabled();
        mMetricsEnabled = deps.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY,
                NetworkStackUtils.VALIDATION_METRICS_VERSION, true /* defaultEnabled */);
        mUseHttps = getUseHttpsValidation();
        mCaptivePortalUserAgent = getCaptivePortalUserAgent();
        mCaptivePortalHttpsUrls = makeCaptivePortalHttpsUrls();
        mCaptivePortalHttpUrls = makeCaptivePortalHttpUrls();
        mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
        mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
        mCaptivePortalFallbackSpecs =
                makeCaptivePortalFallbackProbeSpecs(getCustomizedContextOrDefault());
        mRandom = deps.getRandom();
        // TODO: Evaluate to move data stall configuration to a specific class.
        mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold();
@@ -618,15 +633,18 @@ public class NetworkMonitor extends StateMachine {
        mEvaluatingBandwidthTimeoutMs = getResIntConfig(mContext,
                R.integer.config_evaluating_bandwidth_timeout_ms,
                DEFAULT_EVALUATING_BANDWIDTH_TIMEOUT_MS);

        mConfigurationReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
                    sendMessage(EVENT_RESOURCE_CONFIG_CHANGED);
                }
            }
        };
        // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
        // even before notifyNetworkConnected.
        mLinkProperties = new LinkProperties();
        mNetworkCapabilities = new NetworkCapabilities(null);

        Log.d(TAG, "Starting on network " + mNetwork
                + " with capport HTTPS URL " + Arrays.toString(mCaptivePortalHttpsUrls)
                + " and HTTP URL " + Arrays.toString(mCaptivePortalHttpUrls));
    }

    /**
@@ -872,6 +890,18 @@ public class NetworkMonitor extends StateMachine {
    // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
    // does not entail any real state (hence no enter() or exit() routines).
    private class DefaultState extends State {
        @Override
        public void enter() {
            // Register configuration broadcast here instead of constructor to prevent start() was
            // not called yet when the broadcast is received and cause crash.
            mContext.registerReceiver(mConfigurationReceiver,
                    new IntentFilter(ACTION_CONFIGURATION_CHANGED));
            checkAndRenewResourceConfig();
            Log.d(TAG, "Starting on network " + mNetwork
                    + " with capport HTTPS URL " + Arrays.toString(mCaptivePortalHttpsUrls)
                    + " and HTTP URL " + Arrays.toString(mCaptivePortalHttpUrls));
        }

        @Override
        public boolean processMessage(Message message) {
            switch (message.what) {
@@ -1018,11 +1048,27 @@ public class NetworkMonitor extends StateMachine {
                    mNetworkCapabilities = (NetworkCapabilities) message.obj;
                    suppressNotificationIfNetworkRestricted();
                    break;
                case EVENT_RESOURCE_CONFIG_CHANGED:
                    // RRO generation does not happen during package installation and instead after
                    // the OMS receives the PACKAGE_ADDED event, there is a delay where the old
                    // idmap is used with the new target package resulting in the incorrect overlay
                    // is used. Renew the resource if a configuration change is received.
                    // TODO: Remove it once design to generate the idmaps during package
                    //  installation in overlay manager and package manager is ready.
                    if (checkAndRenewResourceConfig()) {
                        sendMessage(CMD_FORCE_REEVALUATION, NO_UID, 1 /* forceAccept */);
                    }
                    break;
                default:
                    break;
            }
            return HANDLED;
        }

        @Override
        public void exit() {
            mContext.unregisterReceiver(mConfigurationReceiver);
        }
    }

    // Being in the ValidatedState State indicates a Network is:
@@ -1343,7 +1389,9 @@ public class NetworkMonitor extends StateMachine {
                    return HANDLED;
                case CMD_FORCE_REEVALUATION:
                    // The evaluation process restarts via EvaluatingState#enter.
                    return shouldAcceptForceRevalidation() ? NOT_HANDLED : HANDLED;
                    final boolean forceAccept = (message.arg2 != 0);
                    return forceAccept || shouldAcceptForceRevalidation()
                            ? NOT_HANDLED : HANDLED;
                // Disable HTTPS probe and transition to EvaluatingPrivateDnsState because:
                // 1. Network is connected and finish the network validation.
                // 2. NetworkMonitor detects network is partial connectivity and user accepts it.
@@ -2005,10 +2053,10 @@ public class NetworkMonitor extends StateMachine {
        return makeURL(strUrl);
    }

    private String getCaptivePortalServerHttpsUrl() {
        return getSettingFromResource(mCustomizedContext,
                R.string.config_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL,
                mCustomizedContext.getResources().getString(
    private String getCaptivePortalServerHttpsUrl(@NonNull Context context) {
        return getSettingFromResource(context,
                R.string.config_captive_portal_https_url, mCaptivePortalHttpsUrlFromSetting,
                context.getResources().getString(
                R.string.default_captive_portal_https_url));
    }

@@ -2085,10 +2133,10 @@ public class NetworkMonitor extends StateMachine {
     * it has its own updatable strategies to detect captive portals. The framework only advises
     * on one URL that can be used, while NetworkMonitor may implement more complex logic.
     */
    public String getCaptivePortalServerHttpUrl() {
        return getSettingFromResource(mCustomizedContext,
                R.string.config_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL,
                mCustomizedContext.getResources().getString(
    public String getCaptivePortalServerHttpUrl(@NonNull Context context) {
        return getSettingFromResource(context,
                R.string.config_captive_portal_http_url, mCaptivePortalHttpUrlFromSetting,
                context.getResources().getString(
                R.string.default_captive_portal_http_url));
    }

@@ -2124,13 +2172,13 @@ public class NetworkMonitor extends StateMachine {
    }

    @VisibleForTesting
    URL[] makeCaptivePortalFallbackUrls() {
    URL[] makeCaptivePortalFallbackUrls(@NonNull Context context) {
        try {
            final String firstUrl = mDependencies.getSetting(mContext, CAPTIVE_PORTAL_FALLBACK_URL,
                    null);
            final URL[] settingProviderUrls =
                combineCaptivePortalUrls(firstUrl, CAPTIVE_PORTAL_OTHER_FALLBACK_URLS);
            return getProbeUrlArrayConfig(settingProviderUrls,
            return getProbeUrlArrayConfig(context, settingProviderUrls,
                    R.array.config_captive_portal_fallback_urls,
                    R.array.default_captive_portal_fallback_urls,
                    this::makeURL);
@@ -2141,7 +2189,7 @@ public class NetworkMonitor extends StateMachine {
        }
    }

    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs(@NonNull Context context) {
        try {
            final String settingsValue = mDependencies.getDeviceConfigProperty(
                    NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
@@ -2151,7 +2199,7 @@ public class NetworkMonitor extends StateMachine {
                    ? emptySpecs
                    : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs);

            return getProbeUrlArrayConfig(providerValue,
            return getProbeUrlArrayConfig(context, providerValue,
                    R.array.config_captive_portal_fallback_probe_specs,
                    DEFAULT_CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS,
                    CaptivePortalProbeSpec::parseSpecOrNull);
@@ -2162,17 +2210,17 @@ public class NetworkMonitor extends StateMachine {
        }
    }

    private URL[] makeCaptivePortalHttpsUrls() {
    private URL[] makeCaptivePortalHttpsUrls(@NonNull Context context) {
        final URL testUrl = getTestUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
        if (testUrl != null) return new URL[] { testUrl };

        final String firstUrl = getCaptivePortalServerHttpsUrl();
        final String firstUrl = getCaptivePortalServerHttpsUrl(context);
        try {
            final URL[] settingProviderUrls =
                combineCaptivePortalUrls(firstUrl, CAPTIVE_PORTAL_OTHER_HTTPS_URLS);
            // firstUrl will at least be default configuration, so default value in
            // getProbeUrlArrayConfig is actually never used.
            return getProbeUrlArrayConfig(settingProviderUrls,
            return getProbeUrlArrayConfig(context, settingProviderUrls,
                    R.array.config_captive_portal_https_urls,
                    DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS, this::makeURL);
        } catch (Exception e) {
@@ -2183,17 +2231,17 @@ public class NetworkMonitor extends StateMachine {
        }
    }

    private URL[] makeCaptivePortalHttpUrls() {
    private URL[] makeCaptivePortalHttpUrls(@NonNull Context context) {
        final URL testUrl = getTestUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
        if (testUrl != null) return new URL[] { testUrl };

        final String firstUrl = getCaptivePortalServerHttpUrl();
        final String firstUrl = getCaptivePortalServerHttpUrl(context);
        try {
            final URL[] settingProviderUrls =
                    combineCaptivePortalUrls(firstUrl, CAPTIVE_PORTAL_OTHER_HTTP_URLS);
            // firstUrl will at least be default configuration, so default value in
            // getProbeUrlArrayConfig is actually never used.
            return getProbeUrlArrayConfig(settingProviderUrls,
            return getProbeUrlArrayConfig(context, settingProviderUrls,
                    R.array.config_captive_portal_http_urls,
                    DEFAULT_CAPTIVE_PORTAL_HTTP_URLS, this::makeURL);
        } catch (Exception e) {
@@ -2221,21 +2269,20 @@ public class NetworkMonitor extends StateMachine {
     * <p>The configuration resource is prioritized, then the provider value.
     * @param context The context
     * @param configResource The resource id for the configuration parameter
     * @param symbol The symbol in the settings provider
     * @param settingValue The value in the settings provider
     * @param defaultValue The default value
     * @return The best available value
     */
    @Nullable
    private String getSettingFromResource(@NonNull final Context context,
            @StringRes int configResource, @NonNull String symbol, @NonNull String defaultValue) {
            @StringRes int configResource, @NonNull String settingValue,
            @NonNull String defaultValue) {
        final Resources res = context.getResources();
        String setting = res.getString(configResource);

        if (!TextUtils.isEmpty(setting)) return setting;

        setting = mDependencies.getSetting(context, symbol, null);

        if (!TextUtils.isEmpty(setting)) return setting;
        if (!TextUtils.isEmpty(settingValue)) return settingValue;

        return defaultValue;
    }
@@ -2245,17 +2292,20 @@ public class NetworkMonitor extends StateMachine {
     *
     * <p>The configuration resource is prioritized, then the provider values, then the default
     * resource values.
     *
     * @param context The Context
     * @param providerValue Values obtained from the setting provider.
     * @param configResId ID of the configuration resource.
     * @param defaultResId ID of the default resource.
     * @param resourceConverter Converter from the resource strings to stored setting class. Null
     *                          return values are ignored.
     */
    private <T> T[] getProbeUrlArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
            @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) {
        final Resources res = mCustomizedContext.getResources();
        return getProbeUrlArrayConfig(providerValue, configResId, res.getStringArray(defaultResId),
                resourceConverter);
    private <T> T[] getProbeUrlArrayConfig(@NonNull Context context, @NonNull T[] providerValue,
            @ArrayRes int configResId, @ArrayRes int defaultResId,
            @NonNull Function<String, T> resourceConverter) {
        final Resources res = context.getResources();
        return getProbeUrlArrayConfig(context, providerValue, configResId,
                res.getStringArray(defaultResId), resourceConverter);
    }

    /**
@@ -2263,15 +2313,18 @@ public class NetworkMonitor extends StateMachine {
     *
     * <p>The configuration resource is prioritized, then the provider values, then the default
     * resource values.
     *
     * @param context The Context
     * @param providerValue Values obtained from the setting provider.
     * @param configResId ID of the configuration resource.
     * @param defaultConfig Values of default configuration.
     * @param resourceConverter Converter from the resource strings to stored setting class. Null
     *                          return values are ignored.
     */
    private <T> T[] getProbeUrlArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
            String[] defaultConfig, @NonNull Function<String, T> resourceConverter) {
        final Resources res = mCustomizedContext.getResources();
    private <T> T[] getProbeUrlArrayConfig(@NonNull Context context, @NonNull T[] providerValue,
            @ArrayRes int configResId, String[] defaultConfig,
            @NonNull Function<String, T> resourceConverter) {
        final Resources res = context.getResources();
        String[] configValue = res.getStringArray(configResId);

        if (configValue.length == 0) {
@@ -3621,4 +3674,37 @@ public class NetworkMonitor extends StateMachine {
                && captivePortalDataShim.getUserPortalUrlSource()
                == ConstantsShim.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT;
    }

    private boolean checkAndRenewResourceConfig() {
        boolean reevaluationNeeded = false;

        final Context customizedContext = getCustomizedContextOrDefault();
        final URL[] captivePortalHttpsUrls = makeCaptivePortalHttpsUrls(customizedContext);
        if (!Arrays.equals(mCaptivePortalHttpsUrls, captivePortalHttpsUrls)) {
            mCaptivePortalHttpsUrls = captivePortalHttpsUrls;
            reevaluationNeeded = true;
            log("checkAndRenewResourceConfig: update captive portal https urls to "
                    + Arrays.toString(mCaptivePortalHttpsUrls));
        }

        final URL[] captivePortalHttpUrls = makeCaptivePortalHttpUrls(customizedContext);
        if (!Arrays.equals(mCaptivePortalHttpUrls, captivePortalHttpUrls)) {
            mCaptivePortalHttpUrls = captivePortalHttpUrls;
            reevaluationNeeded = true;
            log("checkAndRenewResourceConfig: update captive portal http urls to "
                    + Arrays.toString(mCaptivePortalHttpUrls));
        }

        final URL[] captivePortalFallbackUrls = makeCaptivePortalFallbackUrls(customizedContext);
        if (!Arrays.equals(mCaptivePortalFallbackUrls, captivePortalFallbackUrls)) {
            mCaptivePortalFallbackUrls = captivePortalFallbackUrls;
            // Reset the index since the array is changed.
            mNextFallbackUrlIndex = 0;
            reevaluationNeeded = true;
            log("checkAndRenewResourceConfig: update captive portal fallback urls to"
                    + Arrays.toString(mCaptivePortalFallbackUrls));
        }

        return reevaluationNeeded;
    }
}
+83 −18

File changed.

Preview size limit exceeded, changes collapsed.