JasonWang's Blog

PPP拨号时拿到错误DNS的问题解析

最近碰到一个PPP拨号拿到了假的DNS地址10.11.12.13/14, 之前也发生过一次, 但是一直没有有效的日志, 所以就简单粗暴的做了一个方案: 在PPP拨号进行网络参数协商时, 如果发现拿到了10.11.12.13/14这样的DNS地址就修改为指定的运营商DNS地址. 本来以为万事大吉了, 没想到运营商DNS一改, 问题又暴露了, 好在重现抓到了现场日志, 终于找到了原因. 网上看有原来也有不少人碰到了类似现象(https://bugzilla.redhat.com/show_bug.cgi?id=467004#c31), 在这里简要的描述下整个问题的来龙去脉并给出几种可能的解决方案.

在介绍这个问题的根因之前, 先来了解下PPP协议的一些基本概念.

PPP协议介绍

PPP(Point-to-Point Protocol)是在SLIP(Serial Line Internet Protocol)的基础上发展而来, 其通过在终端与远端(remote peer)之间建立一个IPPP数据链路, 将终端设备接入网络. 早些年上网的时候, 把一个ADSL modem跟电脑连接后, 拿着运营商给的用户名与密码, 然后拨号接入互联网,这里边用到的协议就是PPP.

如何在Android Studio中添加自定义framework.jar?

这两天有一个新的功能需求要实现, 要在Android原生代码的Settings(代码目录android/frameworks/base/core/java/android/provider)数据库添加一个新的数据项, 一个系统应用(独立于Android系统源码编译)需要引用该数据项. 那么, 怎么将新的数据项引用到系统应用中了? <! – more –>

备注: 以下所有的示例都基于Android Studio 3.2/操作系统Ubuntu 18.04.1

首先, 在Android源码中修改完成后, 执行本地编译, 在/android/out目录下, 找到编译产生的新的framework模块的jar包:

1
2
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar

Linux下常用网络工具使用总结

平时在Android/Ubuntu这样的Linux系统中, 经常跟网络打交道, 不可避免的要使用网络工具来定位问题;这里对Linux常用的网络工具进行简单的总结, 方便后续查阅使用. 主要看看以下几个常用的网络工具:

  • ping: 基于ICMP协议, 发送ICMP数据包用于测试网络连通状态
  • traceroute: 基于UDP/ICMP/TCP协议用于跟踪网络连通状态, 打印达到目标地址的路由信息
  • tcpdump : 用于抓取tcp/ip包, 分析网络问题的必需神器
  • iproute2 : 查看/添加/删除当前路由信息
  • netstat: 查看网络状态
  • netcfg: 配置网口(使能网口以及配置IP等)
  • iptables: 网络数据包的过滤以及防火墙策略配置
  • netcat: 用于快速建立TCP/UDP链接,检测网络的连通性
  • iperf: 网络性能测试工具, 用来衡量网络吞吐量/带宽
  • tc: Traffic Control, 用于显示/修改网卡配置的工具
  • curl: 基于libcurl的数据传输工具, 支持HTTP/HTTPS/FTP/RTMP/RTSP/SCP等常见协议
  • iw: 用于显示/设置WiFi设备接口的工具, 比如展示当前设备WiFi热点信息, 主动扫描周围WiFi热点等
  • ethtool: 查看/设置以太网网卡驱动/硬件配置
Android netd工作原理详解

NETD是Android一个专门管理网络链接, 路由/带宽/防火墙策略以及iptables的系统Daemon进程, 其在Anroid系统启动时加载:

1
2
3
4
5
6
7
8

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

socket编程与IO multiplexing

socket通常用于跨进程通信(Inter-Process Communication,IPC),由于其最早BSD Unix发行版中使用,因此也叫做Barkeley sockets。socket封装了底层网络通信协议细节,为上层应用提供了一个统一的接口,按照使用的“域”不同,又分为用于网络通信的internet socket以及用于本地进程通信的Unix domain socket。

那么,如何利用socket实现IPC通信了?在多个客户端的情况下,服务端要如何实现同时响应多个客户请求了,即如何实现多个IO端口的监听(I/O multiplex)?这篇文章,就来看看这两个问题。首先,来看下socket编程的一些基本知识。

HAL binder工作流程-以RILJ/RILD通信为例

Telephony(RIL Java,以下简称RILJ)与RILD(RIL Daemon)的通信在Android OO8.0以前都是基于socket通信,而Android 8.0则是基于HAL binder进行IPC的数据交换。有关RILJ与RILD的工作原理可以参考之前的两篇文章:Android RIL概述以及RILD详解。这篇文章主要分析RILJ与RILD是如何通过HAL Binder进行通信。

RILJ与RILD的通信,服务端是RILD,客户端是RILJ。对于RILD而言,其对应的HAL接口是/android/hardware/interfaces/radio/1.0/IRadio.hal:

深入Android HAL binder

HAL binder是Android O(8.0)专门用于HAL(Hardware Abstract Layer)层(native)进程与其clients之间的通信机制(clients可以是native进程,也可以是Java Framework进程)。 HAL binder替代了早先使用的socket通信,其kernel层实际是基于原有的binder驱动,但为了配合Client与Server之间的数据传输,需要使用特定的中间层HIDL来进行接口与数据的转换。那么,相对之前的HAL通信方式(socket),基于HIDL的HAL通信有什么优势了?从系统架构的角度,HIDL为客户端与服务端提供了清晰的接口;从效率的角度,binder IPC实际在传输数据上只有一次拷贝,而socket实际传输需要两次数据拷贝。

目前Android有两种类型的HAL:

  • binder化的HAL: 利用HIDL(HAL interface Definition Language)来描述HAL接口,Framework层与HAL层通过binder IPC的方式进行通信;如下的HAL模块都是利用binder IPC来进行通信的:

    • android.hardware.biometrics.fingerprint@2.1
    • android.hardware.configstore@1.0
    • android.hardware.dumpstate@1.0
    • android.hardware.graphics.allocator@2.0
    • android.hardware.radio@1.0
    • android.hardware.usb@1.0
    • android.hardware.wifi@1.0
    • android.hardware.wifi.supplicant@1.0
  • 直通式HAL: 基于HIDL或者传统HAL方式来实现,在这种模式下,Framework层与HAL层的通信可以通过IPC的方式进行,也可以使用共享内存的方式在同一个进程内进行(passthrough,直通)。目前有如下两个HAL模块使用直通式方式进行通信:

    • android.hardware.graphics.mapper@1.0
    • android.hardware.renderscript@1.0