http://www.2cto.com/kf/201508/438539.html
最近遇到不少框架问题,比如关于网口的,开机后拔掉有线网,状态栏和设置项中有线网显示图标不会更新,还有双网口的需求,下面就带着这个问题,以跟踪网络状态问题为引线,本篇将贯穿分析Ethernet从上至下的框架结构。因能力和时间有限,文中有分析不到位的地方,十分欢迎大侠们拍砖。
首先看下应用层网络监听相关的app 网络监听一:设置 packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java
设置项网络按钮类定义
网络监听二:statusbar frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
1
2
3
4
5
|
EthernetStateMachine.java -> 网络状态机,用于管理网络状态变化及动作逻辑
EthernetManager.java -> 网络管理器,是app和EthernetService信息交互的桥梁
EthernetInfo.java -> 网络状态参数类,是Parcelable的一个实现
EthernetInfo.aidl -> aidl文件,Manager和service统一使用的数据结构
IEthernetManager.aidl -> aidl文件,用于Manager和service通信
|
1
2
3
4
5
6
7
8
|
private
class
InterfaceStateReceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
if
(intent.getAction().equals(EthernetManager.INTERFACE_STATE_CHANGED_ACTION)) {
...
Intent newIntent =
new
Intent(EthernetManager.NETWORK_STATE_CHANGED_ACTION);
newIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
newIntent.putExtra(EthernetManager.EXTRA_ETHERNET_INFO, ei);
|
1
2
3
4
5
6
|
addState(mRootState);
addState(mIdleState, mRootState);
//addState(mObtainingLinkState, mRootState);
addState(mObtainingIpState, mRootState);
addState(mIPConnectedState, mRootState);
addState(mDisconnectingState, mRootState);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private
void
sendInterfaceStateChangedBroadcast() {
if
(DBG) Slog.d(TAG, Sending INTERFACE_STATE_CHANGED_ACTION
for
+ mEthernetInfo.getName());
Intent intent =
new
Intent(EthernetManager.INTERFACE_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(EthernetManager.EXTRA_ETHERNET_INFO,
new
EthernetInfo(mEthernetInfo));
mContext.sendBroadcast(intent);
}
private
void
setNetworkDetailedState(DetailedState state) {
if
(DBG) Slog.d(TAG, mEthernetInfo.getName() + setDetailed state, old =
+ mEthernetInfo.getDetailedState() + and
new
state= + state);
if
(state != mEthernetInfo.getDetailedState()) {
mEthernetInfo.setDetailedState(state,
null
,
null
);
mEthernetInfo.setIsAvailable(
true
);
sendInterfaceStateChangedBroadcast();
}
}
void
dhcpSuccess(DhcpResults dr) {
if
(DBG) Slog.d(TAG, mEthernetInfo.getName() + DHCP successful);
LinkProperties lp = dr.linkProperties;
...
setNetworkDetailedState(DetailedState.CONNECTED);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
void
updateInterface(EthernetInfo newInfo) {
if
(newInfo ==
null
) {
Slog.e(TAG, Null EthernetInfo);
return
;
}
if
(mAvailableInterface ==
null
) {
Slog.e(TAG, Unable to find statemachine
for
interface
+ newInfo.getName());
return
;
}
sendMessage(mAvailableInterface,
EthernetStateMachine.CMD_UPDATE_INTERFACE,
newInfo);
if
(DBG) Slog.d(TAG, newInfo.getName() + updateInterface done);
}
|
1
2
3
4
5
6
7
8
9
10
11
|
public
EthernetService(Context context) {
mContext = context;
mNetd = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
);
try
{
mNetd.registerObserver(
new
NetworkManagementEventObserver());
}
catch
(RemoteException e) {
Slog.e(TAG, Remote NetworkManagementService error: + e);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
private
class
NetworkManagementEventObserver
extends
INetworkManagementEventObserver.Stub {
public
void
interfaceAdded(String iface) {
if
(DBG) Slog.d(TAG, interfaceAdded: + iface);
addInterface(iface);
}
public
void
interfaceRemoved(String iface) {
if
(DBG) Slog.d(TAG, interfaceRemoved: + iface);
removeInterface(iface);
}
public
void
limitReached(String limitName, String iface) {}
public
void
interfaceClassDataActivityChanged(String label,
boolean
active) {}
public
void
interfaceLinkStateChanged(String iface,
boolean
up) {
if
(DBG) Slog.d(TAG, interfaceLinkStateChanged
for
+ iface + , up = + up);
if
(mAvailableInterface !=
null
&& up) {
//sendMessage(mAvailableInterface,
//EthernetStateMachine.CMD_LINK_UP);
}
}
public
void
interfaceStatusChanged(String iface,
boolean
up) {
if
(DBG) Slog.d(TAG, interfaceStatusChanged
for
+ iface + , up = + up);
//addInterface(iface);
}
public
void
addressUpdated(String address, String iface,
int
flags,
int
scope) {}
public
void
addressRemoved(String address, String iface,
int
flags,
int
scope) {}
}
|
1
2
3
4
5
6
7
|
SystemServer.java
try
{
Slog.i(TAG, NetworkManagement Service);
networkManagement = NetworkManagementService.create(context);
ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
}
catch
(Throwable e) {
reportWtf(starting NetworkManagement Service, e);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
private
static
final
String NETD_SOCKET_NAME = netd;
private
NetworkManagementService(Context context, String socket) {
mContext = context;
if
(simulator.equals(SystemProperties.get(ro.product.device))) {
return
;
}
mConnector =
new
NativeDaemonConnector(
new
NetdCallbackReceiver(), socket,
10
, NETD_TAG,
160
);
mThread =
new
Thread(mConnector, NETD_TAG);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(
this
);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
private
class
NetdCallbackReceiver
implements
INativeDaemonConnectorCallbacks {
@Override
public
void
onDaemonConnected() {
@Override
public
boolean
onEvent(
int
code, String raw, String[] cooked) {
switch
(code) {
case
NetdResponseCode.InterfaceChange:
}
else
if
(cooked[
2
].equals(linkstate) && cooked.length ==
5
) {
// 网络状态变化事件在这里回调处理
notifyInterfaceLinkStateChanged(cooked[
3
], cooked[
4
].equals(up));
return
true
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* Notify our observers of an interface link state change
* (typically, an Ethernet cable has been plugged-in or unplugged).
*/
private
void
notifyInterfaceLinkStateChanged(String iface,
boolean
up) {
final
int
length = mObservers.beginBroadcast();
for
(
int
i =
0
; i < length; i++) {
try
{
mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
}
catch
(RemoteException e) {
}
catch
(RuntimeException e) {
}
}
mObservers.finishBroadcast();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
@Override
public
void
run() {
mCallbackHandler =
new
Handler(FgThread.get().getLooper(),
this
);
while
(
true
) {
try
{
listenToSocket();
}
catch
(Exception e) {
loge(Error in NativeDaemonConnector: + e);
SystemClock.sleep(
5000
);
}
}
}
private
void
listenToSocket()
throws
IOException {
LocalSocket socket =
null
;
try
{
// 创建一个socket
socket =
new
LocalSocket();
LocalSocketAddress address = determineSocketAddress();
socket.connect(address);
// 从socket中获取流数据并处理
InputStream inputStream = socket.getInputStream();
synchronized
(mDaemonLock) {
mOutputStream = socket.getOutputStream();
}
...
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
event.getCode(), event.getRawEvent()));
// 收到流数据时,直接发给主线程,通过NetdCallbackReceiver 对象进行回调处理
@Override
public
boolean
handleMessage(Message msg) {
String event = (String) msg.obj;
try
{
if
(!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {
log(String.format(Unhandled event
'%s'
, event));
}
}
catch
(Exception e) {
loge(Error handling
' + event + '
: + e);
}
return
true
;
}
private
LocalSocketAddress determineSocketAddress() {
// If we're testing, set up a socket in a namespace that's accessible to test code.
// In order to ensure that unprivileged apps aren't able to impersonate native daemons on
// production devices, even if said native daemons ill-advisedly pick a socket name that
// starts with __test__, only allow this on debug builds.
if
(mSocket.startsWith(__test__) && Build.IS_DEBUGGABLE) {
return
new
LocalSocketAddress(mSocket);
}
else
{
return
new
LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
}
}
|
1
2
|
static
const
RegJNIRec gRegJNI[] = {
REG_JNI(register_android_net_LocalSocketImpl),
|
1
2
3
|
connect()
getInputStream()
getOutputStream()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
static
JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{getOption_native, (Ljava/io/FileDescriptor;I)I, (
void
*)socket_getOption},
{setOption_native, (Ljava/io/FileDescriptor;III)V, (
void
*)socket_setOption},
{connectLocal, (Ljava/io/FileDescriptor;Ljava/lang/String;I)V,
(
void
*)socket_connect_local},
{bindLocal, (Ljava/io/FileDescriptor;Ljava/lang/String;I)V, (
void
*)socket_bind_local},
{listen_native, (Ljava/io/FileDescriptor;I)V, (
void
*)socket_listen},
{accept, (Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;, (
void
*)socket_accept},
{shutdown, (Ljava/io/FileDescriptor;Z)V, (
void
*)socket_shutdown},
{available_native, (Ljava/io/FileDescriptor;)I, (
void
*) socket_available},
{pending_native, (Ljava/io/FileDescriptor;)I, (
void
*) socket_pending},
{read_native, (Ljava/io/FileDescriptor;)I, (
void
*) socket_read},
{readba_native, ([BIILjava/io/FileDescriptor;)I, (
void
*) socket_readba},
{writeba_native, ([BIILjava/io/FileDescriptor;)V, (
void
*) socket_writeba},
{write_native, (ILjava/io/FileDescriptor;)V, (
void
*) socket_write},
{getPeerCredentials_native,
(Ljava/io/FileDescriptor;)Landroid/net/Credentials;,
(
void
*) socket_get_peer_credentials}
//,{getSockName_native, (Ljava/io/FileDescriptor;)Ljava/lang/String;,
// (void *) socket_getSockName}
};
int
register_android_net_LocalSocketImpl(JNIEnv *env){}
|