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

Commit 58b6d489 authored by Brian Williammee's avatar Brian Williammee Committed by Android Git Automerger
Browse files

am e2b1b8e2: Merge "Track latency of captive portal checks"

* commit 'e2b1b8e2':
  Track latency of captive portal checks
parents 2021fba4 e2b1b8e2
Loading
Loading
Loading
Loading
+129 −2
Original line number Original line Diff line number Diff line
@@ -28,11 +28,23 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.IConnectivityManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.Message;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Settings;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;


import com.android.internal.util.State;
import com.android.internal.util.State;
@@ -44,6 +56,7 @@ import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.URL;
import java.net.URL;
import java.net.UnknownHostException;
import java.net.UnknownHostException;
import java.util.List;


import com.android.internal.R;
import com.android.internal.R;


@@ -60,12 +73,29 @@ public class CaptivePortalTracker extends StateMachine {


    private static final int SOCKET_TIMEOUT_MS = 10000;
    private static final int SOCKET_TIMEOUT_MS = 10000;


    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
    public static final String EXTRA_CELL_ID = "extra_cellid";
    public static final String EXTRA_SSID = "extra_ssid";
    public static final String EXTRA_BSSID = "extra_bssid";
    /** real time since boot */
    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";

    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
            "android.permission.ACCESS_NETWORK_CONDITIONS";

    private String mServer;
    private String mServer;
    private String mUrl;
    private String mUrl;
    private boolean mNotificationShown = false;
    private boolean mNotificationShown = false;
    private boolean mIsCaptivePortalCheckEnabled = false;
    private boolean mIsCaptivePortalCheckEnabled = false;
    private IConnectivityManager mConnService;
    private IConnectivityManager mConnService;
    private TelephonyManager mTelephonyManager;
    private TelephonyManager mTelephonyManager;
    private WifiManager mWifiManager;
    private Context mContext;
    private Context mContext;
    private NetworkInfo mNetworkInfo;
    private NetworkInfo mNetworkInfo;


@@ -92,6 +122,7 @@ public class CaptivePortalTracker extends StateMachine {
        mContext = context;
        mContext = context;
        mConnService = cs;
        mConnService = cs;
        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mProvisioningObserver = new ProvisioningObserver();
        mProvisioningObserver = new ProvisioningObserver();


        IntentFilter filter = new IntentFilter();
        IntentFilter filter = new IntentFilter();
@@ -319,7 +350,8 @@ public class CaptivePortalTracker extends StateMachine {
    }
    }


    /**
    /**
     * Do a URL fetch on a known server to see if we get the data we expect
     * Do a URL fetch on a known server to see if we get the data we expect.
     * Measure the response time and broadcast that.
     */
     */
    private boolean isCaptivePortal(InetAddress server) {
    private boolean isCaptivePortal(InetAddress server) {
        HttpURLConnection urlConnection = null;
        HttpURLConnection urlConnection = null;
@@ -327,6 +359,7 @@ public class CaptivePortalTracker extends StateMachine {


        mUrl = "http://" + server.getHostAddress() + "/generate_204";
        mUrl = "http://" + server.getHostAddress() + "/generate_204";
        if (DBG) log("Checking " + mUrl);
        if (DBG) log("Checking " + mUrl);
        long requestTimestamp = -1;
        try {
        try {
            URL url = new URL(mUrl);
            URL url = new URL(mUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection = (HttpURLConnection) url.openConnection();
@@ -334,11 +367,26 @@ public class CaptivePortalTracker extends StateMachine {
            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
            urlConnection.setUseCaches(false);
            urlConnection.setUseCaches(false);

            // Time how long it takes to get a response to our request
            requestTimestamp = SystemClock.elapsedRealtime();

            urlConnection.getInputStream();
            urlConnection.getInputStream();

            // Time how long it takes to get a response to our request
            long responseTimestamp = SystemClock.elapsedRealtime();

            // we got a valid response, but not from the real google
            // we got a valid response, but not from the real google
            return urlConnection.getResponseCode() != 204;
            boolean isCaptivePortal = urlConnection.getResponseCode() != 204;

            sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal,
                    requestTimestamp, responseTimestamp);
            return isCaptivePortal;
        } catch (IOException e) {
        } catch (IOException e) {
            if (DBG) log("Probably not a portal: exception " + e);
            if (DBG) log("Probably not a portal: exception " + e);
            if (requestTimestamp != -1) {
                sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
            } // else something went wrong with setting up the urlConnection
            return false;
            return false;
        } finally {
        } finally {
            if (urlConnection != null) {
            if (urlConnection != null) {
@@ -352,12 +400,15 @@ public class CaptivePortalTracker extends StateMachine {
        try {
        try {
            inetAddress = InetAddress.getAllByName(hostname);
            inetAddress = InetAddress.getAllByName(hostname);
        } catch (UnknownHostException e) {
        } catch (UnknownHostException e) {
            sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
            return null;
            return null;
        }
        }


        for (InetAddress a : inetAddress) {
        for (InetAddress a : inetAddress) {
            if (a instanceof Inet4Address) return a;
            if (a instanceof Inet4Address) return a;
        }
        }

        sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
        return null;
        return null;
    }
    }


@@ -414,4 +465,80 @@ public class CaptivePortalTracker extends StateMachine {
        }
        }
        mNotificationShown = visible;
        mNotificationShown = visible;
    }
    }

    private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) {
        sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */,
                requestTimestampMs, 0 /* ignored */);
    }

    /**
     * @param responseReceived - whether or not we received a valid HTTP response to our request.
     * If false, isCaptivePortal and responseTimestampMs are ignored
     */
    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
            long requestTimestampMs, long responseTimestampMs) {
        if (Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
            if (DBG) log("Don't send network conditions - lacking user consent.");
            return;
        }

        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
        switch (mNetworkInfo.getType()) {
            case ConnectivityManager.TYPE_WIFI:
                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
                if (currentWifiInfo != null) {
                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
                } else {
                    if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
                    return;
                }
                break;
            case ConnectivityManager.TYPE_MOBILE:
                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
                if (info == null) return;
                StringBuffer uniqueCellId = new StringBuffer();
                int numRegisteredCellInfo = 0;
                for (CellInfo cellInfo : info) {
                    if (cellInfo.isRegistered()) {
                        numRegisteredCellInfo++;
                        if (numRegisteredCellInfo > 1) {
                            if (DBG) log("more than one registered CellInfo.  Can't " +
                                    "tell which is active.  Bailing.");
                            return;
                        }
                        if (cellInfo instanceof CellInfoCdma) {
                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
                        } else if (cellInfo instanceof CellInfoGsm) {
                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
                        } else if (cellInfo instanceof CellInfoLte) {
                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
                        } else if (cellInfo instanceof CellInfoWcdma) {
                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
                        } else {
                            if (DBG) logw("Registered cellinfo is unrecognized");
                            return;
                        }
                    }
                }
                break;
            default:
                return;
        }
        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkInfo.getType());
        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);

        if (responseReceived) {
            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
        }
        mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
    }
}
}
+8 −0
Original line number Original line Diff line number Diff line
@@ -201,6 +201,7 @@
    <protected-broadcast android:name="android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED" />
    <protected-broadcast android:name="android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED" />
    <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
    <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
    <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
    <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
    <protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
    <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
    <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
    <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
    <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
    <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
    <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
@@ -2399,6 +2400,13 @@
        android:description="@string/permdesc_invokeCarrierSetup"
        android:description="@string/permdesc_invokeCarrierSetup"
        android:protectionLevel="signature|system" />
        android:protectionLevel="signature|system" />


    <!-- Allows an application to listen for network condition observations.
         @hide This is not a third-party API (intended for system apps). -->
    <permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
        android:label="@string/permlab_accessNetworkConditions"
        android:description="@string/permdesc_accessNetworkConditions"
        android:protectionLevel="signature|system" />

    <!-- The system process is explicitly the only one allowed to launch the
    <!-- The system process is explicitly the only one allowed to launch the
         confirmation UI for full backup/restore -->
         confirmation UI for full backup/restore -->
    <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
    <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
+5 −0
Original line number Original line Diff line number Diff line
@@ -1905,6 +1905,11 @@
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <string name="permdesc_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps.</string>
    <string name="permdesc_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps.</string>


    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <string name="permlab_accessNetworkConditions">listen for observations on network conditions</string>
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</string>

    <!-- Policy administration -->
    <!-- Policy administration -->


    <!-- Title of policy access to limiting the user's password choices -->
    <!-- Title of policy access to limiting the user's password choices -->