android linux 网络,Android 使能有线网络 Ethernet

背景

Android kitkat 默认已经支持 Ethernet 有线网络,只要稍微配置,便可以直接使用,测试结果,网络浏览器和下载都没有没有问题,而且系统可以做到与 wifi 共存,互相不影响功能,这里简单介绍如何使能 Ethernet,并简要分析其代码和流程。

Linux 配置部分

Linux 需要能够支持有线网络,生成 eth 网络设备节点。

Android 配置

overlay

主要是 overlay 里面添加 Ethernet 网络类型支持:

frameworks/base/core/res/res/values/config.xml

"1,1"

"7,1"

"9,1"

其中 9 对应 Ethernet 的网络类型,其定义在 ConnectivityManager.java 中

/**

* The Ethernet data connection. When active, all data traffic

* will use this network type's interface by default

* (it has a default route).

*/

public static final int TYPE_ETHERNET = 9;

init..rc

init 里面需要添加 dhcp 和 ip renew 服务

# DHCPCD

# # eth0

service dhcpcd_eth0 /system/bin/dhcpcd -ABKL

class main

disabled

oneshot

# IP Renew

# # eth0

service iprenew_eth0 /system/bin/dhcpcd -n

class main

disabled

oneshot

流程分析

ConnectivityService

ConnectivityService 的构造函数里面将会读取 radioAttributes 里面的网络配置

public ConnectivityService(Context context, INetworkManagementService netManager,

INetworkStatsService statsService, INetworkPolicyManager policyManager,

NetworkFactory netFactory) {

if (DBG) log("ConnectivityService starting up");

// Load device network attributes from resources

String[] raStrings = context.getResources().getStringArray(

com.android.internal.R.array.radioAttributes);

for (String raString : raStrings) {

RadioAttributes r = new RadioAttributes(raString);

if (VDBG) log("raString=" + raString + " r=" + r);

if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {

loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);

continue;

}

if (mRadioAttributes[r.mType] != null) {

loge("Error in radioAttributes - ignoring attempt to redefine type " +

r.mType);

continue;

}

mRadioAttributes[r.mType] = r;

}

根据网络配置数据,将会创建 EthernetDataTracker , 并开始监听 startMonitoring

// Create and start trackers for hard-coded networks

for (int targetNetworkType : mPriorityList) {

final NetworkConfig config = mNetConfigs[targetNetworkType];

final NetworkStateTracker tracker;

try {

tracker = netFactory.createTracker(targetNetworkType, config);

mNetTrackers[targetNetworkType] = tracker;

} catch (IllegalArgumentException e) {

Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)

+ " tracker: " + e);

continue;

}

tracker.startMonitoring(context, mTrackerHandler);

if (config.isDefault()) {

tracker.reconnect();

}

}

EthernetDataTracker

EthernetDataTracker 将会寻找第一个以 eth 开头的有线网络设备,打开并开始做 dhcp

eth\\d

sIfaceMatch = context.getResources().getString(

com.android.internal.R.string.config_ethernet_iface_regex);

try {

final String[] ifaces = mNMService.listInterfaces();

for (String iface : ifaces) {

if (iface.matches(sIfaceMatch)) {

mNMService.setInterfaceUp(iface);

InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);

if (getEthernetCarrierState(iface) == 1) {

mIface = iface;

mLinkUp = true;

mNetworkInfo.setIsAvailable(true);

if (config != null && mHwAddr == null) {

mHwAddr = config.getHardwareAddress();

if (mHwAddr != null) {

mNetworkInfo.setExtraInfo(mHwAddr);

}

}

}

// if a DHCP client had previously been started for this interface, then stop it

NetworkUtils.stopDhcp(iface);

}

}

reconnect();

} catch (RemoteException e) {

Log.e(TAG, "Could not get list of interfaces " + e);

}

DHCP 成功后,通知NetworkManagementService 网路已经连接,这个时候上层应用便可以开始执行网络操作。

mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);

Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);

Android 以太网调用流程

frameworks\base\core\java\android\net\EthernetManager.java

public boolean setEthernetEnabled(boolean enabled) {

Log.d(TAG,enabled ? "turn on Ethernet" : "turn off Ethernet");

try {

return mService.setEthernetEnabled(enabled);

} catch (RemoteException e) {

return false;

}

}

frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetService.java

EthernetServiceImpl.java

public boolean setEthernetEnabled(boolean enable) {

//enforceChangePermission();

Log.i(TAG,"setEthernetEnabled() : enable="+enable);

if ( enable ) {

return mTracker.setInterfaceUp();

} else {

return mTracker.setInterfaceDown();

}

}

EthernetNetworkFactory.java

public boolean setInterfaceUp() {

try {

if(!TextUtils.isEmpty(mIface)) {

mNMService.setInterfaceUp(mIface);

sendEthIfaceStateChangedBroadcast(EthernetManager.ETHER_IFACE_STATE_UP);

return true;

}

else

Log.e(TAG,"mIface is null");

}catch (Exception e) {

Log.e(TAG, "Error downing interface " + mIface + ": " + e);

}

return false;

}

frameworks\base\services\core\java\com\android\server\NetworkManagementService.java

public void setInterfaceUp(String iface) {

mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);

final InterfaceConfiguration ifcg = getInterfaceConfig(iface);

ifcg.setInterfaceUp();

setInterfaceConfig(iface, ifcg);

}

public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {

mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);

LinkAddress linkAddr = cfg.getLinkAddress();

if (linkAddr == null || linkAddr.getAddress() == null) {

throw new IllegalStateException("Null LinkAddress given");

}

final Command cmd = new Command("interface", "setcfg", iface,

linkAddr.getAddress().getHostAddress(),

linkAddr.getPrefixLength());

for (String flag : cfg.getFlags()) {

cmd.appendArg(flag);

}

try {

mConnector.execute(cmd);

} catch (NativeDaemonConnectorException e) {

throw e.rethrowAsParcelableException();

}

}

system\netd\server\CommandListener.cpp

CommandListener::InterfaceCmd::InterfaceCmd() :

NetdCommand("interface") {

}

int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,

int argc, char **argv) {

else if (!strcmp(argv[1], "setcfg")) {

// arglist: iface [addr prefixLength] flags

if (argc < 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);

return 0;

}

ALOGD("Setting iface cfg");

struct in_addr addr;

int index = 5;

ifc_init();

if (!inet_aton(argv[3], &addr)) {

// Handle flags only case

index = 3;

} else {

if (ifc_set_addr(argv[2], addr.s_addr)) {

cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);

ifc_close();

return 0;

}

// Set prefix length on a non zero address

if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) {

cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);

ifc_close();

return 0;

}

}

/* Process flags */

for (int i = index; i < argc; i++) {

char *flag = argv[i];

if (!strcmp(flag, "up")) {

ALOGD("Trying to bring up %s", argv[2]);

if (ifc_up(argv[2])) {

ALOGE("Error upping interface");

cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);

ifc_close();

return 0;

}

} else if (!strcmp(flag, "down")) {

ALOGD("Trying to bring down %s", argv[2]);

if (ifc_down(argv[2])) {

ALOGE("Error downing interface");

cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);

ifc_close();

return 0;

}

} else if (!strcmp(flag, "broadcast")) {

// currently ignored

} else if (!strcmp(flag, "multicast")) {

// currently ignored

} else if (!strcmp(flag, "running")) {

// currently ignored

} else if (!strcmp(flag, "loopback")) {

// currently ignored

} else if (!strcmp(flag, "point-to-point")) {

// currently ignored

} else {

cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);

ifc_close();

return 0;

}

}

cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);

ifc_close();

return 0;

}

return 0;

}

system\core\libnetutils\ifc_utils.c

发送命令到内核;

int ifc_up(const char *name)

{

int ret = ifc_set_flags(name, IFF_UP, 0);

if (DBG) printerr("ifc_up(%s) = %d", name, ret);

return ret;

}

static int ifc_set_flags(const char *name, unsigned set, unsigned clr)

{

struct ifreq ifr;

ifc_init_ifr(name, &ifr);

if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;

ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;

return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);

}

你可能感兴趣的:(android,linux,网络)