Android Ethernet 1 from top to bottom

Source: Internet
Author: User

Android Ethernet 1 from top to bottom
Recently, many framework problems have been encountered, such as network port disconnection after startup. The network display icons in the status bar and settings are not updated, and the dual network port needs to be removed, this article describes the top-to-bottom framework structure of Ethernet. Due to limited capabilities and time, the analysis in this article is not in place. You are very welcome to make a brick.
First, let's take a look at the app network listener related to the application layer network listener 1: Set packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler. java

Set network button class definition

 

Network listener 2: statusbar frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController. java
NetworkController itself is a BroadcastReceiver. The listening message about network status changes is EthernetManager. NETWORK_STATE_CHANGED_ACTION. You can guess that the message was sent by framework.

After the network service framework layer is organized, the network framework manager and Service Code and basic explanations are as follows: frameworks/base/ethernet/java/com/android/internal/ethernet/
EthernetStateMachine. java-> network state machine, used to manage network status changes and Action Logic EthernetManager. java-> network manager, which is a bridge between app and EthernetService information. java-> network status parameter class, which is an implementation of Parcelable EthernetInfo. aidl-> aidl file, IEthernetManager, which is the unified data structure used by managers and services. aidl-> aidl file for Manager and service communication


Here we can find that the network state machine is listening for NETWORK_STATE_CHANGED_ACTION broadcast. The Broadcast Sender is no longer here, so it should be at the service and continue. Frameworks/base/services/java/com/android/server/EthernetService. java
    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);
In the service, you can see the send action of NETWORK_STATE_CHANGED_ACTION, and this send action is not directly started by the underlying reporting status, but is the network state machine mentioned above, which sends the INTERFACE_STATE_CHANGED_ACTION broadcast information, why did the source run again? Some may not understand why a simple event broadcast should be sent back and forth in the framework. Once they understand the role of the network state machine, they will understand the logic of these processes.
We know that statemachine is characterized by a rootstate, which then develops down from multiple states into a tree structure, The transition between States is accompanied by actions such as enter () and processMessage ().. The status initialization of EthernetStateMachine is as follows:
            addState(mRootState);            addState(mIdleState, mRootState);            //addState(mObtainingLinkState, mRootState);            addState(mObtainingIpState, mRootState);            addState(mIPConnectedState, mRootState);            addState(mDisconnectingState, mRootState);

The INTERFACE_STATE_CHANGED_ACTION broadcast mentioned above continues to look at the logic in the state machine. In ethernetstatemachine, State Changes control broadcast notifications of network states., Some code is as follows:
    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);    }

The above is the logic function of the network state machine, and the message source of the state machine is service,
    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);    }
Now we have seen the back-to-back broadcast, which is the end. Note that in the broadcast sending and receiving program, we need to pay attention to the transmission of a serialization parameter, that is EthernetInfo object, which stores the current network status parameters.
We can understand that the network state machine is an auxiliary logical processing unit of EthernetService. The service sends a message to the state machine, waits for the state machine processing result, and then sends the result to the application. This is the general logic of some network framework layers. After learning about this, we continue to analyze where the service gets the network status message. Let's take a look at the EthernetService constructor:
    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);        }
Let's take a look at the implementation of NetworkManagementEventObserver:
    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) {}    }
Here we can see that seivice performs function callback from NetworkManagementService. NetworkManagementService is also a service item registered to the system. As the name suggests, it is responsible for the Network Management Service. The specific functions are not analyzed in depth in this article. One of them interacts with netd through socket, and this will be tracked later.
    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);    }
In the subsequent analysis, we began to understand the interaction between the framework and native. Here we first look at a network diagram.


Let's take a look at NetworkManagementService. java at the top of the graph.
    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);    }
The socket value here is the netd string. The service starts the Runnable thread named nativedaemonconneand transmits the NetdCallbackReceiver object from the constructor to call back and process various network events.
Private class NetdCallbackReceiver implements {@ 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) {// The network status change event is called back here to process yyinterfacelinkstatechanged (cooked [3], cooked [4]. equals (up); return true ;}

   /**     * 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();    }
As mentioned above, NativeDaemonConnector is a Runnable implementation. What does this thread do in the background? In the thread run function, we can see that the thread has been listenToSocket in the while endless loop. We can guess this is where the listener obtains network-related events in native.
@ 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 {// create a socket = new LocalSocket (); LocalSocketAddress address = determineSock EtAddress (); socket. connect (address); // obtain stream data from the socket and process InputStream inputStream = socket. getInputStream (); synchronized (mDaemonLock) {mOutputStream = socket. getOutputStream ();}... mCallbackHandler. sendMessage (mCallbackHandler. obtainMessage (event. getCode (), event. getRawEvent (); // when the stream data is received, it is directly sent to the main thread and called back through the NetdCallbackReceiver object. @ Override public boolean handleMessage (Message msg) {String ev Ent = (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 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 );}}
Next, let's take a look at the LocalSocket-related classes and learn how to connect and get the socket. LocalSocket * related classes are defined in frameworks/base/core/java/android/net/|-> LocalSocket. java
|-> LocalSocketAddress. java |-> LocalSocketImpl. java focuses on the LocalSocketImpl class, where a large number of native functions can be seen, that is, the interaction between java and C ++ through jni. Some may have doubts, since jni is used to call the C ++ library function, the System is not seen here. loadlibary. Based on jni, we know that the jni name used by the java class should be android_net_LocalSocket *. Therefore, the cpp file with this name exists in the android project code, the path is frameworks/base/core/jni /. We can check that the java layer here calls the lib library, and after compilation, we know that the library name is libandroid_runtime.so. So where does the database load? The following is a brief introduction. We know that at android startup, the first process init is parsing init. app_process is created in rc. Before the zygote process is created, app_process establishes the dalvikvm virtual machine environment and initializes the android runtime. libandroid_runtime.so library is loaded in C environment in advance. As follows: frameworks/base/core/jni/AndroidRuntime. cpp
static const RegJNIRec gRegJNI[] = {    REG_JNI(register_android_net_LocalSocketImpl),
After learning about Library Loading, let's look at several important functions used in LocalSocketImpl. java:
connect()getInputStream()getOutputStream()
The specific content of the function is not considerate. You can see that local methods such as read_native () and writeba_native () are called. Now we are at the door of native. Open the local function file and check the local function list in native. Frameworks/base/core/jni/android_net_LocalSocketImpl.cpp
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){}

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.