最近在做类似面对面通信,需要一台手机作为AP端开启热点,另一台手机作为STA端连接热点,然后AP端告诉STA端它的IP地址,进行socket通信。 手机在联网时,就会被分配一个IP地址,它在开启热点时,它本身作为一个“路由器”也会生成一个IP地址,我们需要的就是后面这个IP地址,目前论坛上关于手机IP地址的帖子都是获取手机被分配的IP地址。我在解决这个问题时参考了蓝牙的配置IP地址,函数是configureBtIface(),在/frameworks/base/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java里。可以看到它也是先获取然后配置,参考这个,我写了获取热点IP地址的函数。
private String configureBtIface(boolean enable, String iface) {
Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable);
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
InterfaceConfiguration ifcg = null;
String address = null;
try {
ifcg = service.getInterfaceConfig(iface);
if (ifcg != null) {
InetAddress addr = null;
LinkAddress linkAddr = ifcg.getLinkAddress();
if (linkAddr == null || (addr = linkAddr.getAddress()) == null || addr.equals(
NetworkUtils.numericToInetAddress("0.0.0.0")) || addr.equals(
NetworkUtils.numericToInetAddress("::0"))) {
address = BLUETOOTH_IFACE_ADDR_START;
addr = NetworkUtils.numericToInetAddress(address);
}
ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH));
if (enable) {
ifcg.setInterfaceUp();
} else {
ifcg.setInterfaceDown();
}
ifcg.clearFlag("running");
service.setInterfaceConfig(iface, ifcg);
if (enable) {
int tetherStatus = cm.tether(iface);
if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
Log.e(TAG, "Error tethering " + iface + " tetherStatus: " + tetherStatus);
return null;
}
} else {
int untetherStatus = cm.untether(iface);
Log.i(TAG, "Untethered: " + iface + " untetherStatus: " + untetherStatus);
}
}
}
return address;
}
下面getIpAddress()就是我写的开启热点以后获取AP端IP地址的函数,主要就是把蓝牙那边的参数改成了wlan0,就ok了。经过测试,log打出来的IP地址和手机执行ifconfig里wlan0里面的IP地址一模一样。当然,这个IP地址每次打开热点都是不一样的。在Android8.0以及之前这个IP地址是固定的,好像是"192.168.43.1"。9.0以后随机分配,可能是为了安全吧。
private String getIpAddress() {
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
InterfaceConfiguration ifcg = null;
String address = null;
try {
ifcg = service.getInterfaceConfig("wlan0");
if (ifcg != null) {
LinkAddress linkAddr = ifcg.getLinkAddress();
Log.d("test" , "linkAddr" + linkAddr.toString());
if (linkAddr != null) {
InetAddress Inetaddr = linkAddr.getAddress();
Log.d("test" , "Inetaddr" + Inetaddr.toString());
if (Inetaddr != null) {
address = Inetaddr.getHostAddress();
if (address != null) {
Log.d("test" , "address " + address.toString());
}
}
}
}
} catch (Exception e) {
Log.e("test", "Error configuring interface :" + e);
return null;
}
return address;
}
这里贴上Android9.0上开启热点时分配IP地址(ipv4)的代码:/frameworks/base/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java里的configureIPv4()函数。
private boolean configureIPv4(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
// TODO: Replace this hard-coded information with dynamically selected
// config passed down to us by a higher layer IP-coordinating element.
String ipAsString = null;
int prefixLen = 0;
if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
ipAsString = USB_NEAR_IFACE_ADDR;
prefixLen = USB_PREFIX_LENGTH;
} else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
ipAsString = getRandomWifiIPv4Address();
prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
} else {
// Nothing to do, BT does this elsewhere.
return true;
}
final LinkAddress linkAddr;
try {
final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
if (ifcg == null) {
mLog.e("Received null interface config");
return false;
}
InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
linkAddr = new LinkAddress(addr, prefixLen);
ifcg.setLinkAddress(linkAddr);
if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
// The WiFi stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own
// state.
ifcg.ignoreInterfaceUpDownStatus();
} else {
if (enabled) {
ifcg.setInterfaceUp();
} else {
ifcg.setInterfaceDown();
}
}
ifcg.clearFlag("running");
mNMService.setInterfaceConfig(mIfaceName, ifcg);
} catch (Exception e) {
mLog.e("Error configuring interface " + e);
return false;
}
// Directly-connected route.
final RouteInfo route = new RouteInfo(linkAddr);
if (enabled) {
mLinkProperties.addLinkAddress(linkAddr);
mLinkProperties.addRoute(route);
} else {
mLinkProperties.removeLinkAddress(linkAddr);
mLinkProperties.removeRoute(route);
}
return true;
}