精华内容
下载资源
问答
  • Android系统首选网络类型设置

    千次阅读 2020-11-30 19:46:24
    Android 首选网络类型式默认值的修改方法 源码部分 //设置 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java // Set the preferred network mode to target ...

    Android 首选网络类型式默认值的修改方法

    源码部分

    //设置
    frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    
    // Set the preferred network mode to target desired value or Default
    // value defined in system property
    String val = "";
    String mode;
    for (int phoneId = 0;
            phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) {
        mode = TelephonyManager.getTelephonyProperty(phoneId,
                 "ro.telephony.default_network",
                 Integer.toString(RILConstants.NETWORK_MODE_WCDMA_PREF));
        if (phoneId == 0) {
            val = mode;
        } else {
            val = val + "," + mode;
        }
    }
    loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val);
    
    //网络类型
    frameworks/base/telephony/java/com/android/internal/telephony/RILConstants.java
    
    /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWOR
    /** GSM, WCDMA (WCDMA preferred) */
    int NETWORK_MODE_WCDMA_PREF = 0;
    /** GSM only */
    int NETWORK_MODE_GSM_ONLY = 1;
    /** WCDMA only */
    int NETWORK_MODE_WCDMA_ONLY = 2;
    /** GSM, WCDMA (auto mode, according to PRL) */
    int NETWORK_MODE_GSM_UMTS = 3;
    /** CDMA and EvDo (auto mode, according to PRL) */
    int NETWORK_MODE_CDMA = 4;
    /** CDMA only */
    int NETWORK_MODE_CDMA_NO_EVDO = 5;
    /** EvDo only */
    int NETWORK_MODE_EVDO_NO_CDMA = 6;
    /** GSM, WCDMA, CDMA, and EvDo (auto mode, according to PRL)
    int NETWORK_MODE_GLOBAL = 7;
    /** LTE, CDMA and EvDo */
    int NETWORK_MODE_LTE_CDMA_EVDO = 8;
    /** LTE, GSM and WCDMA */
    int NETWORK_MODE_LTE_GSM_WCDMA = 9;
    /** LTE, CDMA, EvDo, GSM, and WCDMA */
    int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10;
    /** LTE only mode. */
    int NETWORK_MODE_LTE_ONLY = 11;
    /** LTE and WCDMA */
    int NETWORK_MODE_LTE_WCDMA = 12;
    /** TD-SCDMA only */
    int NETWORK_MODE_TDSCDMA_ONLY = 13;
    /** TD-SCDMA and WCDMA */
    int NETWORK_MODE_TDSCDMA_WCDMA = 14;
    /** LTE and TD-SCDMA*/
    int NETWORK_MODE_LTE_TDSCDMA = 15;
    /** TD-SCDMA and GSM */
    int NETWORK_MODE_TDSCDMA_GSM = 16;
    /** TD-SCDMA, GSM and LTE */
    int NETWORK_MODE_LTE_TDSCDMA_GSM = 17;
    /** TD-SCDMA, GSM and WCDMA */
    int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18;
    /** LTE, TD-SCDMA and WCDMA */
    int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19;
    /** LTE, TD-SCDMA, GSM, and WCDMA */
    int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20;
    /** TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
    int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21;
    /** LTE, TDCSDMA, CDMA, EVDO, GSM and WCDMA */
    int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22;
    /** NR 5G only mode */
    int NETWORK_MODE_NR_ONLY = 23;
    /** NR 5G, LTE */
    int NETWORK_MODE_NR_LTE = 24;
    /** NR 5G, LTE, CDMA and EvDo */
    int NETWORK_MODE_NR_LTE_CDMA_EVDO = 25;
    /** NR 5G, LTE, GSM and WCDMA */
    int NETWORK_MODE_NR_LTE_GSM_WCDMA = 26;
    /** NR 5G, LTE, CDMA, EvDo, GSM and WCDMA */
    int NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA = 27;
    /** NR 5G, LTE and WCDMA */
    int NETWORK_MODE_NR_LTE_WCDMA = 28;
    /** NR 5G, LTE and TDSCDMA */
    int NETWORK_MODE_NR_LTE_TDSCDMA = 29;
    /** NR 5G, LTE, TD-SCDMA and GSM */
    int NETWORK_MODE_NR_LTE_TDSCDMA_GSM = 30;
    /** NR 5G, LTE, TD-SCDMA, WCDMA */
    int NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA = 31;
    /** NR 5G, LTE, TD-SCDMA, GSM and WCDMA */
    int NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA = 32;
    /** NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
    int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33;
    
    int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
            "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
    

    默认值设置

    • 修改系统属性
    #卡1用的是22,卡2用的是20
    ro.telephony.default_network=22,20
    
    • 未设置系统属性时
    int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
    -        "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
    +        "ro.telephony.default_network", Integer.toString(NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA)));
    
    • 修改设置数据库
    frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    
    - loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val);
    + loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, 22);
    
    展开全文
  • 深入理解Android系统网络架构

    千次阅读 多人点赞 2019-04-10 15:33:29
    引言:这篇文章以WiFi举例,介绍了Android系统网络架构。其内容包含:网络链路的连接和注册、网络有效性检测和网络优选、Android系统网络防火墙和几种场景下的网络策略等,文章的最后也列举了几种常见的无法上网原因...

    引言:这篇文章以WiFi举例,介绍了Android系统网络架构。其内容包含:网络链路的连接和注册、网络有效性检测和网络优选、Android系统网络防火墙和几种场景下的网络策略等,文章的最后也列举了几种常见的无法上网原因供大家参考。

    一. 基本结构

    1.1 类图

    1.2 WifiService

    WifiManager中公开API的具体实现,提供了WiFi打开与关闭、配置和扫描、连接和断开等方法,其中也包含了对调用者的权限检查,如开关WiFi需要"Manifest.permission.CHANGE_WIFI_STATE"权限等。外部调用方式为:

    WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    

    1.3 WifiStateMachine

    状态机: 状态机是一种用于表示有限个状态以及在这些状态之间转移和动作行为的数学模型。状态机描述了对象在它生命周期内所经历的状态序列,以及在不同状态下如何响应外部事件。使用状态机可以省去代码中一堆的"if-else"判断,这样不仅易于管理,同时也使代码结构更加清晰,易于阅读。

    WifiStateMachine是一个状态机,用于管理WiFi驱动加载、扫描、连接、获取IP、漫游等各个状态。基本的状态如图:("→"的起始端为父状态,终端为子状态;外部消息可以在子→父状态中流动,子状态不处理的消息交由父状态处理)

    各个状态的描述:

    State Description
    DefaultState 初始状态,WiFi 开关没有打开,驱动没有加载。当处于其他状态时,消息由子状态上行可用于日志打印。
    ConnectModeState ConnectModeStateWiFi开关已经打开,驱动已经加载,native中wpa_supplicant已经启动。此时可以进行扫描和连接的操作。
    进入该状态时发送 “android.net.wifi.WIFI_STATE_CHANGED” 广播。
    L2ConnectedState L2是"Level 2"的意思,代表OSI网络模型中的2层即数据链路层。这个状态代表数据链路已经建立完成。
    进入该状态时发送"android.net.wifi.STATE_CHANGE"广播,连接状态是CONNECTING。
    ObtainingIpState DHCP获取IP过程时的状态。
    ConnectedState 已连接状态,当链路建立完成且DHCP配置IP完成后会进入该状态。
    进入该状态时发送"android.net.wifi.STATE_CHANGE"广播,连接状态是CONNECTED。
    RoamingState 漫游状态。如果附近的两个热点名字(ssid)相同,且网络质量达到一定差异化时,系统就会进入漫游状态,连接到另一个热点。
    DisconnectingState 断开中状态。从断开发起到断开成功,处于该状态。
    进入该状态会发送 “android.net.wifi.STATE_CHANGE” 广播,连接状态是DISCONNECTING。
    DisconnectedState 已断开状态。进入该状态时会发送"android.net.wifi.STATE_CHANGE" 广播,连接状态是DISCONNECTED。

    adb连接状态下可以使用 “adb shell dumpsys wifi” 来查看连接WiFi的信息和连接的详细过程,如:

    上一次扫描结果:

    Latest scan results:
        BSSID              Frequency  RSSI    Age      SSID                                 Flags
      80:8d:b7:62:da:12       5765    -52    1.330+   Bytedance Inc                     [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:da:15       5765    -53   94.471    Bytedance AD                      [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:da:14       5765    -53   94.471    jiyunhudong                       [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:da:13       5765    -53   94.471    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:12:d4       5805    -71   94.471    jiyunhudong                       [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:12:d5       5805    -71   94.469    Bytedance AD                      [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:12:d2       5805    -71   94.469+   Bytedance Inc                     [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:12:d3       5805    -71   94.469    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:da:02       2412    -54   94.469    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:43:d2       5260    -81   94.469+   Bytedance Inc                     [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:43:d3       5260    -81   94.468    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:43:d0       5260    -81   94.468                                      [WPA2-PSK-CCMP][ESS]
      80:8d:b7:63:43:d4       5260    -81   94.468    jiyunhudong                       [WPA2-EAP-CCMP][ESS]
      80:8d:b7:63:43:d5       5260    -81   94.468    Bytedance AD                      [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:df:73       5300    -87   94.468    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:60:26:50       5260    -87   94.468                                      [WPA2-PSK-CCMP][ESS]
      80:8d:b7:60:26:52       5260    -86   94.468+   Bytedance Inc                     [WPA2-EAP-CCMP][ESS]
      80:8d:b7:60:26:54       5260    -86   94.467    jiyunhudong                       [WPA2-EAP-CCMP][ESS]
      80:8d:b7:60:26:53       5260    -86   94.467    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
      80:8d:b7:60:26:55       5260    -86   94.467    Bytedance AD                      [WPA2-EAP-CCMP][ESS]
      80:8d:b7:62:da:11       5765    -53   94.467    Bytedance Guest                   [ESS]
      80:8d:b7:63:12:d1       5805    -71   94.467    Bytedance Guest                   [ESS]
      80:8d:b7:62:da:01       2412    -53   94.467    Bytedance Guest                   [ESS]
      80:8d:b7:63:43:d1       5260    -80   94.467    Bytedance Guest                   [ESS]
      80:8d:b7:63:05:22       2437    -68   94.467    Bytedance Guest                   [ESS]
      80:8d:b7:60:26:51       5260    -87   94.466    Bytedance Guest                   [ESS]
      80:8d:b7:63:38:f3       5200    -73   94.466    Bytedance 2.4G                    [WPA2-EAP-CCMP][ESS]
    

    一次L2连接成功的过程:

     rec[34]: time=04-08 21:36:05.811 processed=ConnectModeState org=DisconnectedState dest=<null> what=147462(0x24006) !SUPPLICANT_STATE_CHANGE_EVENT
                                      rt=34877/34863 29 0 SSID: Bytedance Inc BSSID: 00:00:00:00:00:00 nid: 1 state: ASSOCIATING
     rec[35]: time=04-08 21:36:05.910 processed=ConnectModeState org=DisconnectedState dest=<null> what=147462(0x24006) !SUPPLICANT_STATE_CHANGE_EVENT
                                      rt=34976/34962 30 0 SSID: Bytedance Inc BSSID: 00:00:00:00:00:00 nid: 1 state: ASSOCIATED
     rec[38]: time=04-08 21:36:06.055 processed=ConnectModeState org=DisconnectedState dest=<null> what=147462(0x24006) !SUPPLICANT_STATE_CHANGE_EVENT
                                      rt=35121/35108 48 0 SSID: Bytedance Inc BSSID: 80:8d:b7:62:da:12 nid: 1 state: FOUR_WAY_HANDSHAKE
     rec[39]: time=04-08 21:36:06.062 processed=ConnectModeState org=DisconnectedState dest=<null> what=147462(0x24006) !SUPPLICANT_STATE_CHANGE_EVENT
                                      rt=35128/35114 49 0 SSID: Bytedance Inc BSSID: 80:8d:b7:62:da:12 nid: 1 state: GROUP_HANDSHAKE
     rec[40]: time=04-08 21:36:06.066 processed=ConnectModeState org=DisconnectedState dest=ObtainingIpState what=147459(0x24003) !NETWORK_CONNECTION_EVENT
                                      rt=35132/35118 1 0 80:8d:b7:62:da:12 nid=1 "Bytedance Inc"-WPA_EAP
     rec[41]: time=04-08 21:36:06.096 processed=ConnectModeState org=ObtainingIpState dest=<null> what=147462(0x24006) !SUPPLICANT_STATE_CHANGE_EVENT
                                      rt=35163/35149 52 0 SSID: Bytedance Inc BSSID: 80:8d:b7:62:da:12 nid: 1 state: COMPLETED
    

    1.4 ConnectivityService

    ConnectivityService(简称CS)是Android系统中的网络连接大管家,所有类型(如WiFi、Telephony、Ethernet等)的网络都需要注册关联到CS并提供链路请求接口。CS主要提供了以下几个方面的功能:

    • 网络有效性检测(NetworkMonitor)
    • 网络评分与选择(NetworkFactory、NetworkAgent、NetworkAgentInfo)
    • 网口、路由、DNS等参数配置(netd)
    • 向系统及三方提供网络申请接口(ConnectivityManager)

    启动方式:

    // SystemServer.java
    try {
        connectivity = new ConnectivityService(
            context, networkManagement, networkStats, networkPolicy);
        ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
                    /* allowIsolated= */ false,
            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
        networkStats.bindConnectivityManager(connectivity);
        networkPolicy.bindConnectivityManager(connectivity);
    } catch (Throwable e) {
        reportWtf("starting Connectivity Service", e);
    }
    

    外部调用方式:

    ConnectivityManager connectivityManager = 
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    

    adb连接状态下可以通过"adb shell dumpsys connectivity"来查看系统当前所有的网络信息以及网络检测等关键日志:

    Current Networks:
      NetworkAgentInfo{ ni{[type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: "Bytedance Inc", roaming: false, failover: false, isAvailable: true]}  network{100}
      lp{{InterfaceName: wlan0 LinkAddresses: [fe80::5a44:98ff:fef8:74e2/64,10.95.43.48/21,]  Routes: [fe80::/64 -> :: wlan0,10.95.40.0/21 -> 0.0.0.0 wlan0,0.0.0.0/0 -> 10.95.40.1 wlan0,]
      DnsAddresses: [10.2.0.2,10.1.0.2,] Domains: bytedance.net MTU: 0 TcpBufferSizes: 524288,1048576,2097152,262144,524288,1048576 HttpProxy: [10.95.40.10] 8888 xl= }}
      nc{[ Transports: WIFI Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED LinkUpBandwidth>=1048576Kbps LinkDnBandwidth>=1048576Kbps SignalStrength: -54]}
      Score{60}  everValidated{true}  lastValidated{true}  created{true} lingering{false} explicitlySelected{false} acceptUnvalidated{false} everCaptivePortalDetected{false}
      lastCaptivePortalDetected{false} }
        Requests:
          NetworkRequest [ id=1, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
          NetworkRequest [ id=3, legacyType=-1, [] ]
          NetworkRequest [ id=4, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
          NetworkRequest [ id=6, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
          NetworkRequest [ id=7, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
          NetworkRequest [ id=8, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
          NetworkRequest [ id=9, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
        Lingered:
    
    Network Requests:
      Listen from uid/pid:10126/8357 for NetworkRequest [ id=7, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
      Request from uid/pid:1000/2048 for NetworkRequest [ id=1, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
      Listen from uid/pid:1000/3122 for NetworkRequest [ id=3, legacyType=-1, [] ]
      Listen from uid/pid:10126/8357 for NetworkRequest [ id=9, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
      Listen from uid/pid:10126/8357 for NetworkRequest [ id=8, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
      Listen from uid/pid:10126/7970 for NetworkRequest [ id=6, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
      Listen from uid/pid:10126/7873 for NetworkRequest [ id=4, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
    

    1.5 NetworkFactory

    系统中的网络工厂,也是CS向链路网络请求的统一接口。Android系统启动之初,数据和WiFi就通过WifiNetworkFactory和TelephonyNetworkFactory将自己注册到CS中,方便CS迅速响应网络请求。

    NetworkFactory继承自Handler,并通过AsyncChannel(对Messenger的一种包装,维护了连接的状态,本质上使用Messenger)建立了CS和WifiStateMachine之间的单向通信:

    // NetworkFactory.java
    public void register() {
        if (DBG) log("Registering NetworkFactory");
        if (mMessenger == null) {
            // 创建以自己为Handler的Messenger并传递给CS
            // 之后CS就能够使用Messenger通过Binder的形式与WifiStateMachine线程通信
            mMessenger = new Messenger(this);
            ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
        }
    }
    

    CS通过NetworkFactory和WifiStateMachine单向通信:

    对于AsyncChannel可以参考之前整理的一篇博客:
    https://blog.csdn.net/qq_14978113/article/details/80701588

    1.6 NetworkAgent

    链路网络的代理,是CS和链路网络管理者(如WifiStateMachine)之间的信使,在L2连接成功后创建。通过NetworkAgent,WifiStateMachine可以向CS:

    • 更新网络状态 NetworkInfo(断开、连接中、已连接等)
    • 更新链路配置 LinkProperties(本机网口、IP、DNS、路由信息等)
    • 更新网络能力 NetworkCapabilities(信号强度、是否收费等)

    CS可以向WifiStateMachine:

    • 更新网络有效性(即NetworkMonitor的网络检测结果)
    • 禁止自动连接
    • 由于网络不可上网等原因主动断开网络

    因此,NetworkAgent提供了CS和WifiStateMachine之间双向通信的能力。原理类似NetworkFactory,也是使用了AsyncChannel和Messenger。

    CS和WifiStateMachine通过NetworkAgent进行双向通信:

    1.7 NetworkMonitor

    在链路网络注册到CS,并且所有网络配置信息都已经向netd完成了配置,此时就会开始进行网络诊断,具体诊断的任务交给NetworkMonitor。

    NetworkMonitor也是一个状态机,包含以下几种基本状态:

    State Description
    DefaultState 初始状态。接收CS网络诊断命令消息后触发诊断;接收用户登录网络消息
    MaybeNotifyState 通知用户登录。接收诊断后发送的"CMD_LAUNCH_CAPTIVE_PORTAL_APP"消息,startActivity显示登录页面
    EvaluatingState 诊断状态。进入时发送"CMD_REEVALUATE"消息,接收 “CMD_REEVALUATE” 消息并执行网络诊断过程
    CaptivePortalState 登录状态。进入时发送"CMD_LAUNCH_CAPTIVE_PORTAL_APP"消息显示登录页面,
    发送10分钟延迟的"CMD_CAPTIVE_PORTAL_RECHECK"消息进行再次诊断
    ValidatedState 已验证状态。进入时发送"EVENT_NETWORK_TESTED"通知CS网络诊断完成。
    EvaluatingPrivateDnsState 私密DNS验证状态。Android Pie验证私密DNS推出。

    1.8 NetworkPolicyManagerService

    NetworkPolicyManagerService(简称NPMS)是Android系统的网络策略管理者。NPMS会监听网络属性变化(是否收费,metered)、应用前后台、系统电量状态(省电模式)、设备休眠状态(Doze),在这些状态发生改变时,为不同名单内的网络消费者配置不同的网络策略。

    启动方式:

    // SystemServer.java
    try {
        networkPolicy = new NetworkPolicyManagerService(context, mActivityManagerService,
                networkManagement);
        ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
    } catch (Throwable e) {
        reportWtf("starting NetworkPolicy Service", e);
    }
    

    外部调用方式:

    NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(this);
    

    网络策略的基本目的:

    • 在收费网络的情况下省流量
    • 最大可能性的省电
    • 防止危险流量进入

    网络策略中几个重要的名单:

    NameList Description
    mUidFirewallStandbyRules 黑名单,针对前后台应用。此名单中的APP默认REJECT,可配置ALLOW。
    mUidFirewallDozableRules 白名单,针对Doze。此名单中的APP在Doze情况下默认ALLOW。
    mUidFirewallPowerSaveRules 白名单,针对省电模式(由Battery服务提供)。此名单中的APP在省电模式下默认ALLOW,但在Doze情况下仍然REJECT。

    NPMS对网络策略进行统一管理和记录,并配合netd和iptables/ip6tables工具,达到网络限制的目的。

    adb连接状态下可以使用"adb shell dumpsys netpolicy"来查看当前的网络策略:

    System ready: true
    Restrict background: false
    Restrict power: false
    Device idle: false
    Metered ifaces: {}
    Network policies:
      NetworkPolicy{template=NetworkTemplate: matchRule=MOBILE, matchSubscriberIds=[460078...] cycleRule=RecurrenceRule{
                    start=2018-01-11T00:00+08:00[Asia/Shanghai] end=null period=P1M} warningBytes=2147483648
                    limitBytes=-1 lastWarningSnooze=-1 lastLimitSnooze=-1 lastRapidSnooze=-1 metered=true inferred=true}
      NetworkPolicy{template=NetworkTemplate: matchRule=MOBILE, matchSubscriberIds=[460021...] cycleRule=RecurrenceRule{
                    start=2018-01-11T00:00+08:00[Asia/Shanghai] end=null period=P1M} warningBytes=2147483648
                    limitBytes=-1 lastWarningSnooze=-1 lastLimitSnooze=-1 lastRapidSnooze=-1 metered=true inferred=true}
    power save whitelist (except idle) app ids:
      UID=1000: true
      UID=1001: true
      UID=2000: true
      UID=10006: true
      UID=10008: true
      UID=10013: true
      UID=10021: true
    Power save whitelist app ids:
      UID=1000: true
      UID=1001: true
      UID=2000: true
      UID=10013: true
      UID=10021: true
    Default restrict background whitelist uids:
      UID=10013
      UID=10021
      UID=12810021
    

    1.9 NetworkManagementService

    Android SystemServer不具备直接配置和操作网络的能力,所有的网络参数(网口、IP、DNS、Router等)配置,网络策略执行都需要通过netd这个native进程来实际执行或者传递给Kernel来执行。

    而NetworkManagementService(简称NMS)就是SystemServer中其他服务连接netd的桥梁。

    NMS和netd之间通信的方式有两种:Binder 和 Socket。为什么不全使用Binder?原因在于Android老版本上像 vold、netd 这种native进程和SystemServer通信的方式都是使用的Socket,目前高版本上也在慢慢的Binder化,提升调用速度。

    SystemServer和netd之间的数据流向图:

    adb连接状态下可以使用 “adb shell dumpsys network_management” 查看NMS和netd之前通过socket传递的信息记录:

    04-09 15:09:25.609 - SND -> {1331 network create 101}
    04-09 15:09:25.609 - RCV <- {200 1331 success}
    04-09 15:09:25.610 - SND -> {1332 network interface add 101 wlan0}
    04-09 15:09:25.616 - SND -> {1333 traffic wmmer enable}
    04-09 15:09:25.701 - RCV <- {200 1332 success}
    04-09 15:09:25.702 - SND -> {1334 network route add 101 wlan0 fe80::/64}
    04-09 15:09:25.706 - RCV <- {200 1333 command succeeeded}
    04-09 15:09:25.707 - SND -> {1335 traffic limitter enable}
    04-09 15:09:25.707 - RCV <- {200 1334 success}
    04-09 15:09:25.708 - SND -> {1336 network route add 101 wlan0 10.95.40.0/21}
    04-09 15:09:25.757 - RCV <- {200 1335 command succeeeded}
    04-09 15:09:25.757 - SND -> {1337 traffic updatewmm 10014 1}
    04-09 15:09:25.757 - RCV <- {200 1336 success}
    04-09 15:09:25.758 - SND -> {1338 network route add 101 wlan0 0.0.0.0/0 10.95.40.1}
    04-09 15:09:25.758 - RCV <- {200 1337 command succeeeded}
    04-09 15:09:25.759 - SND -> {1339 traffic whitelist 10014 add}
    04-09 15:09:25.759 - RCV <- {200 1338 success}
    04-09 15:09:25.761 - RCV <- {200 1339 command succeeeded}
    04-09 15:09:25.762 - SND -> {1340 resolver setnetdns 101 bytedance.net 10.2.0.2 10.1.0.2 240c::6666 114.114.114.114}
    

    1.10 netd

    为了保障各个功能的正常运行,Android系统中有非常多的守护进程(Daemon)。为了保证系统起来后各项功能都已经ready,这些daemon进程跟随系统的启动而启动,而且一般比system_server进程先启动。如存储相关的vold、电话相关的rild、以及网络相关netd等。

     root@virgo:/ # ps |grep -E "netd|vold|rild|system_server"
     root      253   1     10268  2464  __sys_trac b6d0a824 S /system/bin/vold
     root      330   1     30600  2884  binder_thr b6c47ac8 S /system/bin/netd
     radio     332   1     59132  11124 __sys_trac b6dba824 S /system/bin/rild
     radio     566   1     57844  11024 __sys_trac b6e9a824 S /system/bin/rild
     system    2048  348   1925344 248952 sys_epoll_ b6ca999c S system_server
    

    init.svc.netd进程由init进程启动,netd.rc 如下:

    service netd /system/bin/netd
        class main
        socket netd stream 0660 root system
        socket dnsproxyd stream 0660 root inet
        socket mdns stream 0660 root system
        socket fwmarkd stream 0660 root inet
        onrestart restart zygote
        onrestart restart zygote_secondary
    

    netd作为Android系统的网络守护者,主要有以下方面的职能:

    • 处理接收来自Kernel的UEvent消息(包含网络接口、带宽、路由等信息),并传递给Framework
    • 提供防火墙设置、网络地址转换(NAT)、带宽控制、网络设备绑定(Tether)等接口
    • 管理和缓存DNS信息,为系统和应用提供域名解析服务

    1.11 wpa_supplicant

    与netd一样,也是Android系统的一个daemon进程,与netd不同的是,它只有在WiFi开启的情况下才会启动,在WiFi关闭的时候会随之关闭。wpa_supplicant向Framework提供了WiFi配置、连接、断开等接口。

    wpa_supplicant比Android的历史要早,在很多其他平台上也被广泛利用,他增加了对更多RFC协议的支持,这也是Google最初选择它的原因。但从Android近几个版本来看,Google还是希望弱化wpa_supplicant,并将其功能迁移至Framework或者其他daemon进程中。Android 8.0发生的几个改变:

    • 与system_server的通信从原来的Socket通信改成了HIDL,提高了速度、便于system分区自升级
    • 扫描的功能迁移到了system/wificond中,弱化wpa_supplicant

    启动方式:

    service wpa_supplicant /system/vendor/bin/hw/wpa_supplicant -g@android:wpa_wlan0
        interface android.hardware.wifi.supplicant@1.0::ISupplicant default
        interface android.hardware.wifi.supplicant@1.1::ISupplicant default
        socket wpa_wlan0 dgram 660 wifi wifi
        class main
        disabled
        oneshot
    

    wpa_supplicant和Framework通信:

    二. 注网过程

    Android系统网络注册过程很复杂,涉及到的模块也非常多。主要可以分为以下几个步骤:

    1. WiFi热点扫描,获取扫描结果
    2. 配置WiFi验证信息,已配置完可忽略
    3. 数据链路层L2连接(包含Associate、FourWay-Handshake、Group-Handshake等过程)
    4. DHCP通过UDP的方式获取IP、Gateway、DNS等网络信息
    5. 配置Interafce、IP、DNS、Router到netd

    2.1 WiFi链路连接

    以自动连接为例:

    扫描流程:

    在Android系统中,WiFi扫描的方式主要有三种:

    1. 前台扫描:亮屏状态下且在WiFi Settings页面,每10s发起一次扫描
    2. 后台扫描:亮屏状态下且不在WiFi Settings页面,扫描间隔呈二进制指数退避,退避:interval * (2^n),最短间隔为20s,最长间隔为160s
    3. PNO扫描:灭屏状态下只扫描已保存的网络。最小间隔min=20s,最大间隔max=20s*3

    在Android 8.0 以后,为了解决多种扫描类型带来的冗杂,Google推出了 WifiScanningService,在其中维护了3个状态机分别应用上述3种扫描:WifiSingleScanStateMachine 、WifiBackgroundScanStateMachine、WifiPnoScanStateMachine。

    AP选择流程:

    假如设备中保存了多个可以上网的网络,并且当前都可以被扫描到,系统如何保证连接上最佳(网络质量最高、用户最想要连接)的网络呢?

    Ans:WifiNetworkSelector提供了AP优选的能力,影响优选的因素有:

    1. 是否被用户由于无法上网而UnWanted,进入了禁止自动连接的黑名单
    2. 信号是否过弱,2.4GHz下不低于-80dBm,5GHz下不低于-77dBm
    3. 其他因素一致情况下,5GHz比2.4GHz享有 40 分加成
    4. 上次用户主动选择的AP享有最高 480 分加成,根据时长递减
    5. 根据信号衰减值(rssi)计算信号分加成(rssi + 85)* 4
    6. 与当前连接的AP一致享有 24 分加成
    7. 非开放网络享有 80 分加成

    连接流程:

    Android WiFi的连接过程主要分为 链路连接 和 DHCP获取IP 两个过程。(如果使用的是静态IP则不需要进行DHCP)

    WiFi链路连接:

    (图片来自:https://blog.csdn.net/QQ474111624/article/details/86620579

    1. 认证:对于WPA-PSK、WPA2-PSK类型网络使用密码(Pre-shared key)进行认证;对于EAP类型(PEAP、TTLS、PWD、TLS)则根据具体的加密方法需要身份、密码、证书等进行认证。

    2. 关联:由STA向AP发出关联请求,AP回应关联请求。STA和AP建立关联后,后续数据报文的收发则只能与关联的AP进行。

      注:对于开放类型的网络,这时候链路就已经连理成功了。

    3. 四路握手:PTK(Pairwise Transient Key,成对临时密钥,用于加密单播数据流的加密密钥)的生成、交换、安装。

    4. 组握手:GTK(Group Temporal Key, 组临时密钥,用于加密广播和组播数据流的加密密钥)的生成、交换、安装。


    DHCP获取IP: 动态主机设置协议(Dynamic Host Configuration Protocol,DHCP)是一个局域网内的网络协议,使用UDP协议工作,主要用于内部网或网络服务供应商自动分配IP地址。DHCP流程:

    1. DHCP DISCOVER:DHCP客户机发送有限广播请求IP。(0.0.0.0:68 → 255.255.255.255:67)

    2. DHCP OFFER:DHCP服务器响应。在收到客户机的DHCP请求后,DHCP服务器从IP地址池中找出合法可用的IP地址填入DHCP OFFER报文中并发送有限广播给客户机。(192.168.1.1:67 → 255.255.255.255:68)

    3. DHCP REQUEST:DHCP客户机选择IP。DHCP客户机从接收到的DHCP OFFER消息中选择IP地址,并发送DHCP REQUEST有限广播到所有的DHCP服务器,表明它接受提供的内容。(0.0.0.0:68 → 255.255.255.255:67)

    4. DHCP ACK:DHCP服务器确认租约。(192.168.1.1:67 → 255.255.255.255:68)


    Android系统中为DHCP创建的协议族为IPPROTO_UDP的Socket:

    // DhcpClient.java
    private boolean initUdpSocket() {
        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
        try {
            // UDP数据报
            mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
            Os.setsockoptIfreq(mUdpSock, SOL_SOCKET, SO_BINDTODEVICE, mIfaceName);
            // 广播
            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
            // Inet4Address.ANY: 0.0.0.0
            // DhcpPacket.DHCP_CLIENT: 68
            Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
            NetworkUtils.protectFromVpn(mUdpSock);
        } catch(SocketException|ErrnoException e) {
            Log.e(TAG, "Error creating UDP socket", e);
            return false;
        } finally {
            TrafficStats.setThreadStatsTag(oldTag);
        }
        return true;
    }
    

    2.2 WiFi注网

    WiFi、Data、Ethernet等类型链路网络注册到CS,并将Interface、IP、DNS、Router等网络属性设置到netd中的过程称为Android系统的注网过程。

    前面已经提到WifiStateMachine和CS之间是通过WifiNetworkAgent使用AsyncChannel来进行双向通信的,这里不再赘述。

    注网流程图:

    网络属性设置到netd的Socket通信记录可以通过 “adb shell dumpsys network_management” 来查看。如前文所说,Framework和netd通信有Socket和Binder两种方式,在网络注册这个过程中,DNS的设置在Android O版本前后发生了变化,O以前的版本使用Socket,而O以后的版本使用的是Binder,如下所示:

    Android M:

    04-09 15:09:25.609 - SND -> {1331 network create 101}
    04-09 15:09:25.609 - RCV <- {200 1331 success}
    04-09 15:09:25.610 - SND -> {1332 network interface add 101 wlan0}
    04-09 15:09:25.701 - RCV <- {200 1332 success}
    04-09 15:09:25.702 - SND -> {1334 network route add 101 wlan0 fe80::/64}
    04-09 15:09:25.707 - RCV <- {200 1334 success}
    04-09 15:09:25.708 - SND -> {1336 network route add 101 wlan0 10.95.40.0/21}
    04-09 15:09:25.757 - RCV <- {200 1336 success}
    04-09 15:09:25.758 - SND -> {1338 network route add 101 wlan0 0.0.0.0/0 10.95.40.1}
    04-09 15:09:25.759 - RCV <- {200 1338 success}
    // 使用socket的方式,在"dumpsys network_management"中有该记录
    04-09 15:09:25.762 - SND -> {1340 resolver setnetdns 101 bytedance.net 10.2.0.2 10.1.0.2 240c::6666 114.114.114.114}
    

    Android O:

    2019-04-09T17:38:48.692 - SND -> {149271 network create 314}
    2019-04-09T17:38:48.692 - RCV <- {200 149271 success}
    2019-04-09T17:38:48.878 - SND -> {149277 network interface add 314 wlan0}
    2019-04-09T17:38:48.963 - RCV <- {200 149277 success}
    2019-04-09T17:38:48.965 - SND -> {149278 network route add 314 wlan0 fe80::/64}
    2019-04-09T17:38:48.966 - RCV <- {200 149278 success}
    2019-04-09T17:38:48.968 - SND -> {149279 network route add 314 wlan0 10.95.48.0/21}
    2019-04-09T17:38:48.969 - RCV <- {200 149279 success}
    2019-04-09T17:38:48.969 - SND -> {149280 network route add 314 wlan0 0.0.0.0/0 10.95.48.1}
    2019-04-09T17:38:48.970 - RCV <- {200 149280 success}
    // 没有setnetdns的记录,因为这个过程使用了Binder的通信方式
    

    2.3 连接状态及相关广播

    以WiFi举例,对于应用开发者来说,有3个网络相关的广播比较重要:

    Class Broadcast Description
    WifiManager.java android.net.wifi.WIFI_STATE_CHANGED WiFi开关状态的改变(打开、打开中、关闭、关闭中)
    WifiManager.java android.net.wifi.STATE_CHANGE WiFi连接状态的改变(已连接、连接中、已断开、断开中),“已连接” 不代表此时可以上网。
    ConnectivityManager.java android.net.conn.CONNECTIVITY_CHANGE 网络(不只是WiFi)连接状态的改变(连接、断开),“已连接” 代表此时可以上网。

    这三个广播都是粘性广播,通过Context.sendStickyBroadcast来发送,因此应用在注册该广播时,如果之前有发送过该广播,就一定会收到一次广播通知。

    Note:不要通过 “android.net.wifi.STATE_CHANGE” 来判断是否可以上网,因为链路成功后是不能代表此时可以支持上网的,需要等待CS配置完成并发送 “android.net.conn.CONNECTIVITY_CHANGE” 的广播后才可能上网。


    三. 网络优选/评分

    3.1 网络有效性检测

    每种类型的链路网络在L2连接上并注册到CS中时,CS都会为其匹配一个NetworkMonitor,用于进行网络有效性检测。NetworkMonitor将检测结果反馈给CS,CS会根据结果进行以下过程:

    • 标记和提示用户网络有效性状态
    • 提示用户进入网络二次登录操作(针对Portal类型网络,如机场WiFi)
    • 为网络进行评分,并进行网络切换,提供最优网络

    触发网络有效性检测的时机:

    • 链路连接上并且Interface/IP/Router/DNS等配置成功后触发检测
    • 网络检测不通过时延时触发检测
    • Portal类型网络登录后触发检测
    • 三方APP通过CS的reportNetworkConnectivity接口反馈网络有效性触发检测

    检测方式实际就是通过HTTP请求下面域名进行的:

    // NetworkMonitor.java
    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
    private static final String DEFAULT_HTTP_URL      =
            "http://connectivitycheck.gstatic.com/generate_204";
    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
    private static final String DEFAULT_OTHER_FALLBACK_URLS =
            "http://play.googleapis.com/generate_204";
    

    网络有效性检测的原理:

    1. DNS验证:使用"Network.getAllByName(host)"进行DNS解析,成功则验证通过,抛出"UnknownHostException"异常则说明验证失败。

    2. HTTP验证:使用HttpURLConnection访问generate_204网站(访问成功会返回204的response code),该网站一般使用Google提供的"http://connectivitycheck.gstatic.com/generate_204",各大手机厂商也会进行定制,防止被墙导致诊断失误。HTTP验证会有3种结果,根据response code确定:

    • code=204:返回值由generate_204网站返回,网络验证通过
    • 200<=code<=399:返回值由路由器网关返回,一般会携带redirect url,网络需要登录
    • code不在上述范围内:无法上网
    • 抛出"IOException",无法上网

    网络有效性检测的主要流程: (下图描述了某个需要二次登录认证网络的有效性检测过程)

    3.2 评分机制

    CS中注册的网络可能不只一种,同时,CS也能够向Data和WiFi提供的NetworkFactory请求链路网络。多种网络共存时,就存在优先选择的问题,CS通过分数统计的方式来进行网络择优。评分的影响因素有:

    1. 链路网络存在初始分数:WiFi默认为60分,Data默认为50分
    2. 链路网络根据信号衰减rssi更新初始分数
    3. 用户强行选择的网络(不可上网但用户主动连接)默认100分
    4. 网络是否可以上网,不可上网则减去40分
    // NetworkAgentInfo.java
    private int getCurrentScore(boolean pretendValidated) {
        if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
            // 用户主动选择,一般是摄像机、车载WiFi等设备
            // 直接返回100分
            return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;
        }
    
        // currentScore为链路网络的初始分数,受rssi影响
        int score = currentScore;
        if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) 
        {
            // 不可上网,减去40分
            score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
        }
        if (score < 0) score = 0;
        return score;
    }
    

    当前的分数影响到网络选择,以WiFi和Data举例,

    如果当前连接Data:由于score小于WiFI的默认分数60,向WifiNetworkFactory请求网络,并保持当前网络直到WiF连接重新触发网络验证、评分和网络选择。

    如果当前连接WiFi:

    1. score > 50:保持使用WiFi,如果Data连接着且没有"针对性"(NetworkRequest中存在"TRANSPORT_CELLULAR"选项)请求,则断开Data网络
    2. score < 50:保持使用WiFi,并向TelephonyNetworkFactory请求Data网络,Data连上后重新触发网络验证、评分和网络选择

    注明:Android O上开始在CS中默认保留一个 “TRANSPORT_CELLULAR” 的mDefaultMobileDataRequest,除非用户主动关闭数据网络,否则将一直保持数据链路的连接状态,方便在WiFi状态不佳时进行WiFi和Data之间的快速切换。


    四. 网络策略/防火墙

    为了达到省电/省流量/拦截等目的,Android系统会在多种场景下(Doze、Powersave、前后台等)根据配置进行网络流量限制。

    4.1 Netfilter和iptables

    Android基于Linux内核,而Linux则使用Netfilter这个"钩子"在内核的IP协议栈中去hook各个阶段的数据包,根据预先制定的包过滤规则,定义哪些数据包可以接收,哪些数据包需要丢弃或者拒绝。

    iptables/ip6tables:iptables/ip6tables是用户层的一个工具,用户层使用iptables/ip6tables通过socket的系统调用方式(setsockopt、getsockopt)获取和修改Netfilter需要的包过滤规则,是用户层和内核层Netfilter之间交互的工具。(iptables用于IPv4,ip6tables用于IPv6)

    Netfilter和iptables是Linux网络防火墙中重要的组成部分。Netfilter的工作流程:

    (图片来自:http://blog.chinaunix.net/uid-23069658-id-3160506.html

    收到的每个数据包都从(1)进来,经过路由判决,如果是发送给本机的就经过(2),然后往协议栈的上层继续传递;否则,如果该数据包的目的地不是本机,那么就经过(3),然后顺着(5)将该包转发出去。Netfilter在 PRE_ROUTING、LOCAL_IN、LOCAL_OUT、FORWARD、POST_ROUTING 这5个阶段分别设置回调函数(hook函数),对每一个进出的数据包进行检测。


    q:为什么不只在PRE_ROUTING和POST_ROUTING这两个入口和出口设置数据包检测?

    ans:一方面,这两个阶段处于网络层(IP层)协议栈中,这时候不会拆解TCP/UDP等传输层协议的头部信息,如果需要对更上层协议内容(如端口等)进行过滤,在这两个阶段显然不行;
    另一方面,这两个阶段协议栈不知道这个数据包是需要转发给谁,是转发到下一跳还是传递给上层协议栈,如果是需要传递给上层应用,就更不知道需要传递给哪个应用了。但这些信息在LOCAL_IN和LOCAL_OUT这两个阶段是明确的(明确了传输层协议类型、源IP/目的IP、源端口/目的端口,确定了一条连接),这样过滤应用的报文就成为了可能。


    Netfilter主要有3个模块和3张表:

    1. 包过滤子模块:对应filter表,能够对数据包进行过滤,DROP/REJECT/RETURN/ACCEPT
    2. NAT子模块:对应nat表,能够实现网络地址转换(这个在运营商服务主机中很常用,路由器中其实也运用了该功能,如你手机的外网IP是120.52.148.57,但内网IP是192.168.1.100,这个时候就需要进行网络地址转换)
    3. 数据报修改和跟踪模块:对应mangle表,能够对数据包打上或者判断mark标记,也可以修改数据报中的其它内容(如IP协议头部的tos等)。

    应用层通过iptables工具修改filter、nat和mangle这三张表来控制Netfilter的行为。


    iptables和Netfilter交互方式:

    iptables的源码在/external/iptables目录下,编译完成后,iptables在系统中是一个可执行的bin文件,位于/system/bin目录下:

    root@virgo:/ # ls -lZ system/bin |grep -E "iptables|ip6tables"
    -rwxr-xr-x root     shell             u:object_r:system_file:s0 ip6tables
    lrwxr-xr-x root     shell             u:object_r:system_file:s0 ip6tables-restore -> ip6tables
    lrwxr-xr-x root     shell             u:object_r:system_file:s0 ip6tables-save -> ip6tables
    -rwxr-xr-x root     shell             u:object_r:system_file:s0 iptables
    lrwxr-xr-x root     shell             u:object_r:system_file:s0 iptables-restore -> iptables
    lrwxr-xr-x root     shell             u:object_r:system_file:s0 iptables-save -> iptables
    

    iptables和Netfilter通信使用的是sockopt的系统调用方式,通过setsockopt和getsockopt在参数中传递对应命令值来进行修改和查询:

    (图片来自:http://blog.chinaunix.net/uid-23069658-id-3160506.html

    内核中定义了iptables sockopt的相关命令值:

    // ./include/uapi/linux/netfilter_ipv4/ip_tables.h
    /*
     * New IP firewall options for [gs]etsockopt at the RAW IP level.
     * Unlike BSD Linux inherits IP options so you don't have to use a raw
     * socket for this. Instead we check rights in the calls.
     *
     * ATTENTION: check linux/in.h before adding new number here.
     */
    #define IPT_BASE_CTL        64
    
    // 修改ip tables规则
    #define IPT_SO_SET_REPLACE  (IPT_BASE_CTL)
    // 加入流量计数器
    #define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
    #define IPT_SO_SET_MAX      IPT_SO_SET_ADD_COUNTERS
    
    // 获取ip tables某种类型的表信息
    #define IPT_SO_GET_INFO         (IPT_BASE_CTL)
    // 获取ip tables规则信息
    #define IPT_SO_GET_ENTRIES      (IPT_BASE_CTL + 1)
    #define IPT_SO_GET_REVISION_MATCH   (IPT_BASE_CTL + 2)
    #define IPT_SO_GET_REVISION_TARGET  (IPT_BASE_CTL + 3)
    #define IPT_SO_GET_MAX          IPT_SO_GET_REVISION_TARGET
    

    以iptables获取某个表的规则信息为例:

    // ./external/iptables/libiptc/libiptc.c
    struct xtc_handle *TC_INIT(const char *tablename)
    {
            // 表所有信息数据结构,包含info和规则等
            struct xtc_handle *h;
            // 表基本信息数据结构
            STRUCT_GETINFO info;
            unsigned int tmp;
            socklen_t s;
            int sockfd;
    retry:
            iptc_fn = TC_INIT;
            //...
            sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
            //...
            s = sizeof(info);
    
            // 把tablename复制到info中,用于告知Netfilter查询的是哪张表
            strcpy(info.name, tablename);
            
            // 使用getsockopt的系统调用方式,其中IPT命令为SO_GET_INFO,对应内核
            // 中定义的IPT_SO_GET_INFO,调用完成后,表信息通过info参数返回
            if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
                    close(sockfd);
                    return NULL;
            }
    
            if ((h = alloc_handle(info.name, info.size, info.num_entries))
                == NULL) {
                    close(sockfd);
                    return NULL;
            }
    
            /* Initialize current state */
            h->sockfd = sockfd;
            h->info = info;
    
            h->entries->size = h->info.size;
    
            tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
    
            // 使用getsockopt的系统调用方式,其中IPT命令为SO_GET_ENTRIES,对应内核
            // 中定义的IPT_SO_GET_ENTRIES,调用完成后,规则信息通过h->entries参数返回
            if (getsockopt(h->sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
                           &tmp) < 0)
                    goto error;
    
            if (parse_table(h) < 0)
                    goto error;
    
            CHECK(h);
            return h;error:
            TC_FREE(h);
            /* A different process changed the ruleset size, retry */
            if (errno == EAGAIN)
                    goto retry;
            return NULL;
    }
    

    当然,native层并不需要这么复杂的去操作ip tables,这些都已经被iptables工具封装好了。系统中如netd这些native进程甚至我们在root shell下使用iptables命令就可以操作,如使用"iptables -t filter -L"查看filter表信息:

    root@virgo:/ # iptables -t filter -L
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    bw_INPUT   all  --  anywhere             anywhere
    fw_INPUT   all  --  anywhere             anywhere
    tc_limiter  all  --  anywhere             anywhere
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination
    oem_fwd    all  --  anywhere             anywhere
    fw_FORWARD  all  --  anywhere             anywhere
    bw_FORWARD  all  --  anywhere             anywhere
    natctrl_FORWARD  all  --  anywhere             anywhere
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    wmsctrl_OUTPUT  tcp  --  anywhere             anywhere
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    DROP       udp  --  anywhere             anywhere             udp dpt:1900 /* Drop SSDP on WWAN */
    oem_out    all  --  anywhere             anywhere
    fw_OUTPUT  all  --  anywhere             anywhere
    

    这个过程其实就是fork了iptables子进程并执行了其main函数,并且携带了"-t filter -L"等args参数。


    注明:Google、各大ODM及手机厂商都会配置很多包过滤规则来进行定制化,因此iptables的操作会很频繁,每次fork都会占用比较大的时间资源;并且为了保证并发访问修改内核的ip tables规则时的安全性,iptables中其实是有文件锁(#define XT_LOCK_NAME "/system/etc/xtables.lock")存在的,这样就又存在排队等待。这个过程比较耗时甚至可能还会引起上层的系统watchdog。

    Google在Android O上做了优化:netd中fork出一个iptables-restore进程并且保持它的存活,每次需要时都通过socket的方式将命令发送给该子进程,并且在执行连续执行命令时做了优化,尽可能保证一次查询一次修改。大大优化了效率。如下是系统中的iptables-restore进程,他的父进程是netd:

    HWEML:/ $ ps -A |grep -E "iptables|netd"
    root           569     1 2163632   4320 0                   0 S netd
    root          9071   569   13040   2788 0                   0 S iptables-restore
    

    4.2 前后台网络策略

    前面介绍NetworkPolicyManagerService时提到了一个mUidFirewallStandbyRules数组名单,这里面缓存了后台需要限制上网的uid黑名单。

    NameList Description
    mUidFirewallStandbyRules 黑名单,针对前后台应用。此名单中的APP默认REJECT,可配置ALLOW。
    mUidFirewallDozableRules 白名单,针对Doze。此名单中的APP在Doze情况下默认ALLOW。
    mUidFirewallPowerSaveRules 白名单,针对省电模式(由Battery服务提供)。此名单中的APP在省电模式下默认ALLOW,但在Doze情况下仍然REJECT。

    可以使用"adb shell dumpsys network_management"来查看mUidFirewallStandbyRules名单:

    root@virgo:/ # dumpsys network_management
    UID firewall standby chain enabled: true
    UID firewall standby rule: [10055:2,10104:2,10108:2,10111:2,10116:2,10123:2,10125:2,10126:2,10127:2]
    

    前后台网络策略最终通过filter表中的fw_standby这个名单来控制,该名单与mUidFirewallStandbyRules名单保持一致:

    root@virgo:/ # iptables -t filter -L fw_standby
    Chain fw_standby (2 references)
    target     prot opt source               destination
    DROP       all  --  anywhere             anywhere             owner UID match u0_a55
    DROP       all  --  anywhere             anywhere             owner UID match u0_a104
    DROP       all  --  anywhere             anywhere             owner UID match u0_a108
    DROP       all  --  anywhere             anywhere             owner UID match u0_a111
    DROP       all  --  anywhere             anywhere             owner UID match u0_a116
    DROP       all  --  anywhere             anywhere             owner UID match u0_a123
    DROP       all  --  anywhere             anywhere             owner UID match u0_a125
    DROP       all  --  anywhere             anywhere             owner UID match u0_a126
    DROP       all  --  anywhere             anywhere             owner UID match u0_a127
    RETURN     all  --  anywhere             anywhere
    

    fw_stanby这条chain是黑名单,Netfilter会将数据包的信息与该名单规则(UID匹配)一条条匹配,匹配到就会执行DROP操作,也就是丢弃数据包;如果所有的名单规则都未匹配,则匹配最后一条没有限定条件的规则,执行RETURN操作,也就是放行数据包。"2 references"表示被另外两条chain(fw_INPUT和fw_OUTPUT)引用,只有链接到Netfilter直接操作的chain上时该名单才能够生效。


    注明:只有在非充电情况下fw_standy这条chain才会生效,也就是被fw_INPUT和fw_OUTPUT这两条chain引用,否则fw_standy就会显示"0 references"。可以通过 “adb shell dumpsys battery unplug” 来取消USB充电,然后使用 “adb shell iptables -t filter -L fw_standby” 来查看。


    4.3 Doze下网络策略

    Doze下的网络策略由NetworkPolicyManagerService中的mUidFirewallDozableRules控制,对应filter表中的fw_dozable chain,这是个白名单,符合名单中任何一条UID规则的数据包都会被放行,否则匹配到最后一条默认规则,被丢弃。这个白名单也是可配置的,将一些关键应用(如微信、QQ等需要在休眠时也能接收消息)配置在其中,防止Doze情况下这些应用无法上网,影响用户使用。

    正常情况下,fw_dozable这条chain不会被使用(0 references):

    root@virgo:/ # iptables -t filter -L fw_dozable
    Chain fw_dozable (0 references)
    target     prot opt source               destination
    RETURN     all  --  anywhere             anywhere             owner UID match 0-9999
    RETURN     all  --  anywhere             anywhere             owner UID match radio
    RETURN     all  --  anywhere             anywhere             owner UID match finddevice
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a0
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a1
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a2
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a3
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a4
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a5
    

    当系统进入Doze模式时,fw_dozable就会被使用并且Add到fw_INPUT和fw_OUTPUT中(2 references):

    Chain fw_dozable (2 references)
    target     prot opt source               destination
    RETURN     all  --  anywhere             anywhere             owner UID match 0-9999
    RETURN     all  --  anywhere             anywhere             owner UID match radio
    RETURN     all  --  anywhere             anywhere             owner UID match finddevice
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a0
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a1
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a2
    RETURN     all  --  anywhere             anywhere             owner UID match u0_a3
    ....
    DROP       all  --  anywhere             anywhere
    

    Netfilter将数据包与fw_dozable中的名单一条条匹配,当UID符合规则时,则RETURN,也就是放行;如果数据包的归属者UID都不满足fw_dozable中的规则,则执行最后一条默认的DROP规则,数据包被丢弃。


    注:可以使用 "adb shell dumpsys deviceidle force-idle deep"来进入Doze模式

    root@virgo:/ # dumpsys deviceidle force-idle deep
    Now forced in to deep idle mode
    

    五. 无法上网原因

    最后,简单罗列几种可能导致无法上网的原因:

    1. WiFi网络未验证(portal网络),访问时路由器会重定向到二次登录网址
    2. 运营商服务器或代理服务器问题,无法连接到外网
    3. DNS服务器问题,导致DNS解析失败
    4. 系统时间不正常,导致证书失效,SSL/TLS握手失败,HTTPS无法上网
    5. TCP连接长时间无数据收发,达到NAT超时时间,网络运营商切断TCP连接,导致长连接失效(push心跳间隔应小于NAT超时时间)
    6. 应用进入了后台且在mUidFirewallStandbyRules黑名单中,数据包被DROP
    7. 系统进入省电模式且应用不在mUidFirewallPowerSaveRules白名单中,数据包被DROP
    8. 系统进入Doze且应用不在mUidFirewallDozableRules白名单中,数据包被DROP
    展开全文
  • android通过访问网络获取网络时间,并修改系统时间
  • Android Tv wifi网络登录认证

    千次阅读 2019-09-25 16:03:02
    现在商铺、酒店等公共场所的wifi 网络大多数都需要进行网络登录认证,但在android Tv上面系统设置上的wifi模块好像没有对此场景做出处理,必须要Tv上面安装了浏览器才能进行登录认证,为了解决用户的体验,所以在...

    Android Tv wifi网络登录认证

    前言

    现在商铺、酒店等公共场所的wifi 网络大多数都需要进行网络登录认证,但在android Tv上面系统设置上的wifi模块好像没有对此场景做出处理,必须要Tv上面安装了浏览器才能进行登录认证,为了解决用户的体验,所以在wifi模块添加自动弹出网络登录认证功能是很有必要的。

    网络认证的步骤

    1. 连接wifi成功后请求服务器进行判断是否需要网络登录认证。

    2. 需要网络登录认证,打开webView 调转到网络认证登录网站。

    1.判断wifi是否需要网络登录认证。

    android 默认的请求服务器有2个 (前提是手机厂商没有修改这个默认的服务器)。

    1. http://connectivitycheck.gstatic.com/generate_204
    2. http://www.google.com/gen_204

    对服务器进行请求,获取数据是否需要认证:如果返回204则不需要认证网络。

      /**
         * 判断wifi是否需要Portal认证
         *
         * @return true  false
         */
        public static boolean getWifiSetPortal(String Url) {
            int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 2500;
            HttpURLConnection urlConnection = null;
            int code = 0;
            try {
                URL url = new URL(Url);
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setInstanceFollowRedirects(false);
                urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
                urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
                urlConnection.setUseCaches(false);
                urlConnection.getInputStream();
                code = urlConnection.getResponseCode();
                return code != 204;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
        }
    

    如果需要稳妥一点话,可以对2个服务器依次进行请求。

      public static boolean isWifiSetPortal() {
            if (!getWifiSetPortal(DEFAULT_HTTP_URL)) {
               return !getWifiSetPortal(DEFAULT_FALLBACK_URL);
            }
            return false;
        }
    

    2.需要网络登录认证,打开webView 调转到网络认证登录网站。

    /**
     * webView 网络认证界面
     */
    
    public class CaptivePortalLoginActivity extends Activity {
    
        private WebView mWifiLoginWeb;
        private String url = "http://www.baidu.com/";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_portal);
            mWifiLoginWeb = (WebView) findViewById(R.id.wifi_login_web);
            setWeb();
            mWifiLoginWeb.loadUrl(url);
        }
    
        private void setWeb() {
            final WebSettings webSettings = mWifiLoginWeb.getSettings();
            webSettings.setJavaScriptEnabled(true);
            webSettings.setBuiltInZoomControls(true);
            webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
            mWifiLoginWeb.setVisibility(View.VISIBLE);
            webSettings.setSupportZoom(true);
            webSettings.setDomStorageEnabled(true);
            mWifiLoginWeb.requestFocus();
            webSettings.setUseWideViewPort(true);
            webSettings.setLoadWithOverviewMode(true);
            webSettings.setSupportZoom(true);
            webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
            mWifiLoginWeb.setWebViewClient(new WebViewClient() {
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    Log.d("setweb", url);
                    return false;
                }
            });
        }
    
    }
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <WebView
            android:id="@+id/wifi_login_web"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </WebView>
    </FrameLayout>
    

    启动wifi 登录activity之后,会自动的跳转到网络登录界面,然后用户需要输入用户名和秘密点击登录。

    展开全文
  • 基于Android系统的IPv6网络接入分析

    万次阅读 2017-05-27 23:46:41
    基于Android系统的IPv6网络接入分析 摘 要:本文深入分析了Android设备接入IPv6网络对硬件、软件的一些要求,以及目前Android软件对IPv6网络的支持情况。指出了Android系统的DHCP客户端的一些不足之处,并提出了...

                                                                      基于Android系统的IPv6网络接入分析

    摘 要:本文深入分析了Android设备接入IPv6网络对硬件、软件的一些要求,以及目前Android软件对IPv6网络的支持情况。指出了Android系统的DHCP客户端的一些不足之处,并提出了相应解决方案。

    关键词:Android;IPv6;TCP/IP

    一、 IPv6网络简介

       1.1 IPv6网络的由来

          互联网自1968年诞生之日起,便以TCP/IP网络协议为基础在快速的发展,由于互联网上的主机数目不间断的增加,越来越多的主机需要分配网络地址以实现互联互通,IPv4网络地址资源数量不足的弊端也因此逐渐开始暴露出来。鉴于此,IETF(互联网任务工程组)开始着手规划并设计了用于迭代IPv4协议的下一代IPv6网络协议技术解决方案,IPv6网络协议方案的的实现与投入使用,成功的解决了IP地址缺乏、网络设备接入互联网不兼容的难题。

       1.2 移动设备与移动网络

           随着移动互联网的兴起,研究移动设备的IPv6接入具有深刻意义,移动智能手机作为此类设备的主要组成部分,探讨智能手机对于IPv6的支持不仅会加深对于网络的理解而且会促进IPv6的发展。

    二、 Android系统中网络的概况

         2.1 Android平台架构简介

             Android系统平台是由美国的Google公司和开放手机联盟领导的团队专门为移动便携式设备开发设计的一款基于Linux系统的嵌入式操作系统平台。Android系统在Linux内核架构的基础上不仅采用了Yaffs2文件系统、添加了针对相关移动设备特殊编写的驱动程序,而且还优化了Linux系统中的相关源码,使其更适合于移动便携式终端的使用。

           Android系统的框架结构大体上分为四个层次,分别为Application层、Application Framework层、Librarys层和Linux Kernel层 。其Linux Kernel层主要用来提供上层系统与底层硬件之间交互相关的一些服务,主要包括硬件安全防护机制、内存分配策略管理、操作系统进程管理、网络连接管理以及相关必备的硬件驱动模块实现等。

        2.2 Android网络支持

           2.2.1 底层支持

             Linux系统的Kernel从2.2版本开始就在源代码级别上实现了IPv6网络协议,对其有着完善的支持,Google公司的Android 1.0系统基于Linux Kernel 2.6版本,所以自然在底层源码级别上也是支持此种类型的网络的,出于APP的稳定性等原因考虑,在Android系统的4.0版本之前,Google并没有使Android在Application Framework层支持IPv6协议,并且修改了底层的源码,修改之后的源码经编译后并不能直接支持IPv6网络协议。继Android 4.0版本之后,Google再次修改Android的网络协议模块相关代码,使得Android平台支持了IPv6网络协议,但是由于大部分的应用在设计时未考虑对下一代网络协议的支持,所以,将手机的网络环境更换至IPv6网络环境下时,绝大多数的应用不能再继续正常使用。典型的在IPv6环境下可使用的工具有浏览器,命令行工具。

        2.2.2 实验依据

             Android系统采用双栈协议方式进行IPv4/IPv6网络的切换工作,使用socket方式供移动设备接入网络,在Java层,既提供了IPv4的socket,又提供了IPv6的socket,其根据不同地网络类型进行自动的选择。由于Android系统的DHCP客户端目前在IPv6协议方面的功能还不是很完善,因此,在进行Android设备的IPv6网络连接实验时,需要配置好路由器的相关参数,以及对客户端进行正确的配置,以便使Android设备能够正确的获取到IPv4和IPv6地址。

    三、 Android的IPv6连接实验过程

       3.1 硬件设备     

        1、购买了华为的IPv6路由器,经参数验证确认该设备可以进行基于IPv6协议的网络环境的搭建,用作实验中的网络信号接入源。

        2、实验中使用的手机是小米4手机,手机型号为MI 4LTE,基于Android6.0,其完整的手机参数示意图如下图所示;经参数验证,该手机的系统和基带模块具备实验条件。

     

    3.2 Android手机连接到IPv6网络

         3.2.1  路由器的配置

           将路由器的WAN口通过网络连接线连接到学校的交换机上面,并对路由器进行正确的配置,使其可以正常的进行网络信号的发射,设置其SSID为AHUT_IPV6,以此来标识此网络为采用IPv6协议的网络。

        3.2.2  设备进行网络连接的详细过程

          将实验手机的WLAN功能开关打开,进行无线网络的搜索,当发现此网络后会尝试进行网络的自动连接,如下图所示。

     

           在搜索到AHUT_IPV6网络并进行连接的过程中,实验手机的提示为正在获取当前网络的IP地址,经数分钟后提示连接失败,由此可知,目前Android系统的DHCP客户端对IPv6网络环境相关设置做的还不是很完善,当获取不到IPv4网络地址时,也不能自动的设置IPv6的相关网络参数。Android的网络设置要求必须能获取到IPv4地址,然后才可以正常的设置IPv6的相关参数。了解了DHCP客户端的限制后,采取的方法有两种,一为重新购买路由器,使其发出的无线网络含有IPv4/IPv6网络;二为手动设置手机设备的IPv4地址,这样,DHCP就不会再获取到IPv6地址后一直试图去获取IPV4地址,本实验采用方法二,手动设置小米手机4的IPv4地址,如下图所示。

     

             这样设置后,实验中使用的手机就可以完成IPv6网络的连接,连接后的手机界面如下图所示,从获取到的网络地址也可以验证Android采用双栈协议进行不同协议网络的连接。

     

       3.2.3 对网络的连通性进行测试

        将电脑和手机同时连接在同一网络环境下,对实验手机和电脑进行ping连通性实验测试,在此环境下,设备可以正常的ping通电脑,如下图所示,由图可知,手机和电脑在实验环境下可以进行正常的数据发送,由此可以证明实验理论的正确性。

     

    四、 实验总结

           1、目前采用Android 4.0之后的移动端设备使用IPv6网络可以进行正常的通信,但是,目前Android手机上面支持IPv6协议的的应用软件非常少。

           2、Android采用双栈协议进行IPv4/IPv6网络的协同工作,当发送的是IPv4数据报文时,采用的Socket为v4版本,当发送的数据报文采用的是IPv6协议时,采用的Socket为v6版本。

           3、目前针对移动设备打造的Android系统的DHCP(动态主机配置协议)客户端功能做的还不是很善,有一些不足之处,在只有IPv6网络环境的条件下,需要手动将手机的DHCP客户端IP设置调整为静态,并设置IPv4地址,这样手机的DHCP客户端就不会再尝试获取IPv4地址了。

    展开全文
  • 对于window测试网络吞吐量的工具 http://download.csdn.net/download/leekwen/3427386 iperf windows版测试软件。 针对wifi性能进行测试。 操作举例: 1)TCP测试 服务器执行:#iperf -s -i...
  • Android - 获取系统时间和网络时间

    万次阅读 2017-06-06 18:08:51
    Android - 获取系统时间和网络时间
  • android 安卓系统

    千次阅读 2012-02-23 11:07:49
    Android是一种以Linux为基础的开放源码操作系统,主要使用于便携设备。目前尚未有统一中文名称,中国大陆地区较多人使用安卓(非官方)或安致(官方)。Android操作系统最初由Andy Rubin开发,最初主要支持手机。...
  • Android系统下抓取网络通信包

    千次阅读 2012-08-15 18:03:03
    下面来动手实践一下,如何抓取android系统网络通信包。 一:准备  软件名称:  tcpdump :抓包工具 【点击下载】  WireShark:PC上抓包也是解包的工具 【点击下载】  adb.zip:android调试工具...
  • android调用系统网络设置界面. 实例。
  • Android - 跳转系统网络设置

    千次阅读 2015-09-15 15:53:34
    全部网络设置(ACTION_WIRELESS_SETTINGS); WIFI设置(ACTION_WIFI_SETTINGS); 3G流量设置: (ACTION_DATA_ROAMING_SETTINGS). 发送Intent, 系统接收并跳转.整体: startActivity(new Intent(Settings.ACTION_...
  • Android8.1原生系统网络感叹号消除

    万次阅读 2018-06-19 17:53:20
    原生系统Android8.1上,WiFi上出现感叹号,此时WiFi可正常访问。 原因 这是Android 5.0引入的网络评估机制:就是当你连上网络后,会给目标产生204响应的服务器发送给一个请求,如果服务器返回的是状态码为204...
  • 本文介绍如何通过网络(尤指无线网络)与Android的adbd进行连接。 原理: adb server: 计算机上的一个服务进程,进程名为adb adb daemon: Android 手机上的一个服务进程,进程名为adbd adb client: 你可以认为是...
  • 据来自分析公司Statcounter的研究发现,从网络使用上看,安卓Android)首次超过Windows成为第一大操作系统。在2017年3月期间,从Statcounter的网络活跃度看,谷歌的安卓系统占比37.93%,超过了微软的Windows系统的...
  • Android系统连接WIFI显示网络连接受限

    千次阅读 2021-04-17 16:22:10
    使用Android设备打开设置,选择WIFI输入正确密码连接,会显示已连接,无网络,然后变成网络连接受限,实际可以使用此WIFI进行上网。 问题分析 异常Log D NetworkMonitor/100: PROBE_DNS ...
  • Glide 网络加载图片未显示问题处理 在安卓9.0系统中 http图片偶尔加载不出来的问题 可用下面方法: android:usesCleartextTraffic=“true” 不行的话 在做下面处理 后来发现glide加载url为http开头的图片常常...
  • * 检查网络是否可用 *  * @return true可用,false不可用 */ public static boolean isNetworkValidate(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context...
  • Android打开系统设置界面 转自点击打开链接 方法 1 :startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); 方法 2:Intent intent = new Intent("/");  ComponentName cm = new ...
  • Android 系统当前时间与网络时间同步

    千次阅读 2020-04-30 13:25:51
    在开发系统设置时,需要手动设置系统时间和使用网络时间来进行同步,这时候就需要来获取网络时间进行设置了 代码如下: URL url = new URL("http://www.baidu.com");//取得资源对象 URLConnection uc = url.open...
  • Android系统手机端抓网络数据包方法

    千次阅读 2013-09-27 10:38:06
    一种是否获得root权限的检验方法:安装并打开终端模拟器(可通过安卓市场等渠道获得)。在终端模拟器界面输入su并回车,若报错则说明未root,若命令提示符从$变#则为rooted; 开发人员可以通过在命令行下输入adb ...
  • Android模拟登录教务系统(强智系统)

    千次阅读 2019-01-21 22:08:54
    在这里我将模仿此功能使用J2V8、Jsoup等第三方库实现模拟登录教务系统读取信息。 这里的教务系统以南昌大学教务系统(湖南强智科技教务系统)为例。 现在的大多数网站架构都是后台使用Session来进行用户验证,并...
  •  一台已经获得root权限的安卓手机,并且安卓系统版本在 2.3 以上  busyBox 安装软件 下载地址 BusyBox 是一个集成了一百多个最常用linux命令和工具的软件。[百度百科] 安装这个软件主要是为dsploit软件的运行...
  • Android 9系统,限制了明文流量的网络请求,因为安卓新版本默认是不允许使用明文网络传输的,会强制让应用都使用 https,非加密的流量请求都会被系统禁止,即默认禁止所有 http 请求,需要在 AndroidManifest.xml ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 276,504
精华内容 110,601
关键字:

安卓系统登录网络